Add support for Xilinx Zynq UltraScale+ MPSOC
authorSoren Brinkmann <[email protected]>
Mon, 7 Mar 2016 04:16:27 +0000 (20:16 -0800)
committerSoren Brinkmann <[email protected]>
Wed, 6 Apr 2016 17:44:27 +0000 (10:44 -0700)
The Xilinx Zynq UltraScale+ MPSOC containes a quad A53 cluster. This
patch adds the platform port for that SoC.

Signed-off-by: Soren Brinkmann <[email protected]>
25 files changed:
docs/plat/xilinx-zynqmp.md [new file with mode: 0644]
plat/xilinx/zynqmp/aarch64/zynqmp_common.c [new file with mode: 0644]
plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S [new file with mode: 0644]
plat/xilinx/zynqmp/bl31_zynqmp_setup.c [new file with mode: 0644]
plat/xilinx/zynqmp/include/plat_macros.S [new file with mode: 0644]
plat/xilinx/zynqmp/include/platform_def.h [new file with mode: 0644]
plat/xilinx/zynqmp/plat_psci.c [new file with mode: 0644]
plat/xilinx/zynqmp/plat_topology.c [new file with mode: 0644]
plat/xilinx/zynqmp/plat_zynqmp.c [new file with mode: 0644]
plat/xilinx/zynqmp/platform.mk [new file with mode: 0644]
plat/xilinx/zynqmp/pm_service/pm_api_sys.c [new file with mode: 0644]
plat/xilinx/zynqmp/pm_service/pm_api_sys.h [new file with mode: 0644]
plat/xilinx/zynqmp/pm_service/pm_client.c [new file with mode: 0644]
plat/xilinx/zynqmp/pm_service/pm_client.h [new file with mode: 0644]
plat/xilinx/zynqmp/pm_service/pm_common.h [new file with mode: 0644]
plat/xilinx/zynqmp/pm_service/pm_defs.h [new file with mode: 0644]
plat/xilinx/zynqmp/pm_service/pm_ipi.c [new file with mode: 0644]
plat/xilinx/zynqmp/pm_service/pm_ipi.h [new file with mode: 0644]
plat/xilinx/zynqmp/pm_service/pm_svc_main.c [new file with mode: 0644]
plat/xilinx/zynqmp/pm_service/pm_svc_main.h [new file with mode: 0644]
plat/xilinx/zynqmp/sip_svc_setup.c [new file with mode: 0644]
plat/xilinx/zynqmp/tsp/tsp-zynqmp.mk [new file with mode: 0644]
plat/xilinx/zynqmp/tsp/tsp_plat_setup.c [new file with mode: 0644]
plat/xilinx/zynqmp/zynqmp_def.h [new file with mode: 0644]
plat/xilinx/zynqmp/zynqmp_private.h [new file with mode: 0644]

diff --git a/docs/plat/xilinx-zynqmp.md b/docs/plat/xilinx-zynqmp.md
new file mode 100644 (file)
index 0000000..997d9a9
--- /dev/null
@@ -0,0 +1,49 @@
+ARM Trusted Firmware for Xilinx Zynq UltraScale+ MPSoC
+================================
+
+ARM Trusted Firmware implements the EL3 firmware layer for Xilinx Zynq
+UltraScale + MPSoC.
+The platform only uses the runtime part of ATF as ZynqMP already has a
+BootROM (BL1) and FSBL (BL2).
+
+BL31 is ATF.  
+BL32 is an optional Secure Payload.  
+BL33 is the non-secure world software (U-Boot, Linux etc).  
+
+To build:
+```bash
+make ERROR_DEPRECATED=1 RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=zynqmp bl31
+```
+
+To build bl32 TSP you have to rebuild bl31 too:
+```bash
+make ERROR_DEPRECATED=1 RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=zynqmp SPD=tspd bl31 bl32
+```
+
+# ZynqMP platform specific build options
+*   `ZYNQMP_ATF_LOCATION`: Specifies the location of the bl31 binary. Options:
+    -   `tsram` : bl31 will be located in OCM (default)
+    -   `tdram` : bl31 will be located in DRAM (address: 0x30000000)
+
+*   `ZYNQMP_TSP_RAM_LOCATION`: Specifies the location of the bl32 binary and
+    secure payload dispatcher. Options:
+    -   `tsram` : bl32/spd will be located in OCM (default)
+    -   `tdram` : bl32/spd will be located in DRAM (address: 0x30000000)
+
+# Power Domain Tree
+The following power domain tree represents the power domain model used by the
+ATF for ZynqMP:
+```
+                +-+
+                |0|
+                +-+
+     +-------+---+---+-------+
+     |       |       |       |
+     |       |       |       |
+     v       v       v       v
+    +-+     +-+     +-+     +-+
+    |0|     |1|     |2|     |3|
+    +-+     +-+     +-+     +-+
+```
+The 4 leaf power domains represent the individual A53 cores, while resources
+common to the cluster are grouped in the power domain on the top.
diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
new file mode 100644 (file)
index 0000000..0a878c3
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arch_helpers.h>
+#include <cci.h>
+#include <debug.h>
+#include <gicv2.h>
+#include <mmio.h>
+#include <plat_arm.h>
+#include <platform.h>
+#include <xlat_tables.h>
+#include "../zynqmp_private.h"
+
+/*
+ * Table of regions to map using the MMU.
+ * This doesn't include TZRAM as the 'mem_layout' argument passed to
+ * configure_mmu_elx() will give the available subset of that,
+ */
+const mmap_region_t plat_arm_mmap[] = {
+       { DEVICE0_BASE, DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
+       { DEVICE1_BASE, DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
+       { CRF_APB_BASE, CRF_APB_BASE, CRF_APB_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
+       {0}
+};
+
+static unsigned int zynqmp_get_silicon_ver(void)
+{
+       unsigned int ver;
+
+       ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET);
+       ver &= ZYNQMP_SILICON_VER_MASK;
+       ver >>= ZYNQMP_SILICON_VER_SHIFT;
+
+       return ver;
+}
+
+unsigned int zynqmp_get_uart_clk(void)
+{
+       unsigned int ver = zynqmp_get_silicon_ver();
+
+       switch (ver) {
+       case ZYNQMP_CSU_VERSION_VELOCE:
+               return 48000;
+       case ZYNQMP_CSU_VERSION_EP108:
+               return 25000000;
+       case ZYNQMP_CSU_VERSION_QEMU:
+               return 133000000;
+       }
+
+       return 100000000;
+}
+
+static unsigned int zynqmp_get_system_timer_freq(void)
+{
+       unsigned int ver = zynqmp_get_silicon_ver();
+
+       switch (ver) {
+       case ZYNQMP_CSU_VERSION_VELOCE:
+               return 10000;
+       case ZYNQMP_CSU_VERSION_EP108:
+               return 4000000;
+       case ZYNQMP_CSU_VERSION_QEMU:
+               return 50000000;
+       }
+
+       return 100000000;
+}
+
+#if LOG_LEVEL >= LOG_LEVEL_NOTICE
+static const struct {
+       unsigned int id;
+       char *name;
+} zynqmp_devices[] = {
+       {
+               .id = 0x10,
+               .name = "3EG",
+       },
+       {
+               .id = 0x11,
+               .name = "2EG",
+       },
+       {
+               .id = 0x20,
+               .name = "5EV",
+       },
+       {
+               .id = 0x21,
+               .name = "4EV",
+       },
+       {
+               .id = 0x30,
+               .name = "7EV",
+       },
+       {
+               .id = 0x38,
+               .name = "9EG",
+       },
+       {
+               .id = 0x39,
+               .name = "6EG",
+       },
+       {
+               .id = 0x40,
+               .name = "11EG",
+       },
+       {
+               .id = 0x50,
+               .name = "15EG",
+       },
+       {
+               .id = 0x58,
+               .name = "19EG",
+       },
+       {
+               .id = 0x59,
+               .name = "17EG",
+       },
+};
+
+static unsigned int zynqmp_get_silicon_id(void)
+{
+       uint32_t id;
+
+       id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET);
+
+       id &= ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK | ZYNQMP_CSU_IDCODE_SVD_MASK;
+       id >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT;
+
+       return id;
+}
+
+static char *zynqmp_get_silicon_idcode_name(void)
+{
+       unsigned int id;
+
+       id = zynqmp_get_silicon_id();
+       for (size_t i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) {
+               if (zynqmp_devices[i].id == id)
+                       return zynqmp_devices[i].name;
+       }
+       return "UNKN";
+}
+
+static unsigned int zynqmp_get_rtl_ver(void)
+{
+       uint32_t ver;
+
+       ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET);
+       ver &= ZYNQMP_RTL_VER_MASK;
+       ver >>= ZYNQMP_RTL_VER_SHIFT;
+
+       return ver;
+}
+
+static char *zynqmp_print_silicon_idcode(void)
+{
+       uint32_t id, maskid, tmp;
+
+       id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET);
+
+       tmp = id;
+       tmp &= ZYNQMP_CSU_IDCODE_XILINX_ID_MASK |
+              ZYNQMP_CSU_IDCODE_FAMILY_MASK |
+              ZYNQMP_CSU_IDCODE_REVISION_MASK;
+       maskid = ZYNQMP_CSU_IDCODE_XILINX_ID << ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT |
+                ZYNQMP_CSU_IDCODE_FAMILY << ZYNQMP_CSU_IDCODE_FAMILY_SHIFT |
+                ZYNQMP_CSU_IDCODE_REVISION << ZYNQMP_CSU_IDCODE_REVISION_SHIFT;
+       if (tmp != maskid) {
+               ERROR("Incorrect XILINX IDCODE 0x%x, maskid 0x%x\n", id, maskid);
+               return "UNKN";
+       }
+       VERBOSE("Xilinx IDCODE 0x%x\n", id);
+       return zynqmp_get_silicon_idcode_name();
+}
+
+static unsigned int zynqmp_get_ps_ver(void)
+{
+       uint32_t ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET);
+
+       ver &= ZYNQMP_PS_VER_MASK;
+       ver >>= ZYNQMP_PS_VER_SHIFT;
+
+       return ver + 1;
+}
+
+static void zynqmp_print_platform_name(void)
+{
+       unsigned int ver = zynqmp_get_silicon_ver();
+       unsigned int rtl = zynqmp_get_rtl_ver();
+       char *label = "Unknown";
+
+       switch (ver) {
+       case ZYNQMP_CSU_VERSION_VELOCE:
+               label = "VELOCE";
+               break;
+       case ZYNQMP_CSU_VERSION_EP108:
+               label = "EP108";
+               break;
+       case ZYNQMP_CSU_VERSION_QEMU:
+               label = "QEMU";
+               break;
+       case ZYNQMP_CSU_VERSION_SILICON:
+               label = "silicon";
+               break;
+       }
+
+       NOTICE("ATF running on XCZU%s/%s v%d/RTL%d.%d at 0x%x%s\n",
+              zynqmp_print_silicon_idcode(), label, zynqmp_get_ps_ver(),
+              (rtl & 0xf0) >> 4, rtl & 0xf, BL31_BASE,
+              zynqmp_is_pmu_up() ? ", with PMU firmware" : "");
+}
+#else
+static inline void zynqmp_print_platform_name(void) { }
+#endif
+
+/*
+ * Indicator for PMUFW discovery:
+ *   0 = No FW found
+ *   non-zero = FW is present
+ */
+static int zynqmp_pmufw_present;
+
+/*
+ * zynqmp_discover_pmufw - Discover presence of PMUFW
+ *
+ * Discover the presence of PMUFW and store it for later run-time queries
+ * through zynqmp_is_pmu_up.
+ * NOTE: This discovery method is fragile and will break if:
+ *  - setting FW_PRESENT is done by PMUFW itself and could be left out in PMUFW
+ *    (be it by error or intentionally)
+ *  - XPPU/XMPU may restrict ATF's access to the PMU address space
+ */
+static int zynqmp_discover_pmufw(void)
+{
+       zynqmp_pmufw_present = mmio_read_32(PMU_GLOBAL_CNTRL);
+       zynqmp_pmufw_present &= PMU_GLOBAL_CNTRL_FW_IS_PRESENT;
+
+       return !!zynqmp_pmufw_present;
+}
+
+/*
+ * zynqmp_is_pmu_up - Find if PMU firmware is up and running
+ *
+ * Return 0 if firmware is not available, non 0 otherwise
+ */
+int zynqmp_is_pmu_up(void)
+{
+       return zynqmp_pmufw_present;
+}
+
+/*
+ * A single boot loader stack is expected to work on both the Foundation ZYNQMP
+ * models and the two flavours of the Base ZYNQMP models (AEMv8 & Cortex). The
+ * SYS_ID register provides a mechanism for detecting the differences between
+ * these platforms. This information is stored in a per-BL array to allow the
+ * code to take the correct path.Per BL platform configuration.
+ */
+void zynqmp_config_setup(void)
+{
+       zynqmp_discover_pmufw();
+       zynqmp_print_platform_name();
+
+       /* Global timer init - Program time stamp reference clk */
+       uint32_t val = mmio_read_32(CRL_APB_TIMESTAMP_REF_CTRL);
+       val |= CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT;
+       mmio_write_32(CRL_APB_TIMESTAMP_REF_CTRL, val);
+
+       /* Program freq register in System counter and enable system counter. */
+       mmio_write_32(IOU_SCNTRS_BASEFREQ, zynqmp_get_system_timer_freq());
+       mmio_write_32(IOU_SCNTRS_CONTROL, IOU_SCNTRS_CONTROL_EN);
+}
+
+uint64_t plat_get_syscnt_freq(void)
+{
+       uint64_t counter_base_frequency;
+
+       /* FIXME: Read the frequency from Frequency modes table */
+       counter_base_frequency = zynqmp_get_system_timer_freq();
+
+       return counter_base_frequency;
+}
diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S b/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S
new file mode 100644 (file)
index 0000000..0afed47
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <asm_macros.S>
+#include <gicv2.h>
+#include <platform_def.h>
+
+       .globl  plat_secondary_cold_boot_setup
+       .globl  plat_is_my_cpu_primary
+
+       /* -----------------------------------------------------
+        * void plat_secondary_cold_boot_setup (void);
+        *
+        * This function performs any platform specific actions
+        * needed for a secondary cpu after a cold reset e.g
+        * mark the cpu's presence, mechanism to place it in a
+        * holding pen etc.
+        * TODO: Should we read the PSYS register to make sure
+        * that the request has gone through.
+        * -----------------------------------------------------
+        */
+func plat_secondary_cold_boot_setup
+       mrs     x0, mpidr_el1
+
+       /* Deactivate the gic cpu interface */
+       ldr     x1, =BASE_GICC_BASE
+       mov     w0, #(IRQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP1)
+       orr     w0, w0, #(IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP0)
+       str     w0, [x1, #GICC_CTLR]
+
+       /*
+        * There is no sane reason to come out of this wfi. This
+        * cpu will be powered on and reset by the cpu_on pm api
+        */
+       dsb     sy
+1:
+       bl      plat_panic_handler
+endfunc plat_secondary_cold_boot_setup
+
+func plat_is_my_cpu_primary
+       mov     x9, x30
+       bl      plat_my_core_pos
+       cmp     x0, #ZYNQMP_PRIMARY_CPU
+       cset    x0, eq
+       ret     x9
+endfunc plat_is_my_cpu_primary
diff --git a/plat/xilinx/zynqmp/bl31_zynqmp_setup.c b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
new file mode 100644 (file)
index 0000000..9c9d18d
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <assert.h>
+#include <bl_common.h>
+#include <bl31.h>
+#include <console.h>
+#include <debug.h>
+#include <errno.h>
+#include <plat_arm.h>
+#include <platform.h>
+#include "zynqmp_private.h"
+
+/*
+ * Declarations of linker defined symbols which will help us find the layout
+ * of trusted SRAM
+ */
+extern unsigned long __RO_START__;
+extern unsigned long __RO_END__;
+
+extern unsigned long __COHERENT_RAM_START__;
+extern unsigned long __COHERENT_RAM_END__;
+
+/*
+ * The next 2 constants identify the extents of the code & RO data region.
+ * These addresses are used by the MMU setup code and therefore they must be
+ * page-aligned.  It is the responsibility of the linker script to ensure that
+ * __RO_START__ and __RO_END__ linker symbols refer to page-aligned addresses.
+ */
+#define BL31_RO_BASE (unsigned long)(&__RO_START__)
+#define BL31_RO_LIMIT (unsigned long)(&__RO_END__)
+
+/*
+ * The next 2 constants identify the extents of the coherent memory region.
+ * These addresses are used by the MMU setup code and therefore they must be
+ * page-aligned.  It is the responsibility of the linker script to ensure that
+ * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols
+ * refer to page-aligned addresses.
+ */
+#define BL31_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__)
+#define BL31_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__)
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+/*
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ */
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+       assert(sec_state_is_valid(type));
+
+       if (type == NON_SECURE)
+               return &bl33_image_ep_info;
+
+       return &bl32_image_ep_info;
+}
+
+/*
+ * Perform any BL31 specific platform actions. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before they
+ * are lost (potentially). This needs to be done before the MMU is initialized
+ * so that the memory layout can be used while creating page tables.
+ */
+void bl31_early_platform_setup(bl31_params_t *from_bl2,
+                              void *plat_params_from_bl2)
+{
+       /* Initialize the console to provide early debug support */
+       console_init(ZYNQMP_UART0_BASE, zynqmp_get_uart_clk(),
+                    ZYNQMP_UART_BAUDRATE);
+
+       /* Initialize the platform config for future decision making */
+       zynqmp_config_setup();
+
+       /* There are no parameters from BL2 if BL31 is a reset vector */
+       assert(from_bl2 == NULL);
+       assert(plat_params_from_bl2 == NULL);
+
+       /*
+        * Do initial security configuration to allow DRAM/device access. On
+        * Base ZYNQMP only DRAM security is programmable (via TrustZone), but
+        * other platforms might have more programmable security devices
+        * present.
+        */
+
+       /* Populate entry point information for BL32 and BL33 */
+       SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0);
+       SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
+       bl32_image_ep_info.pc = BL32_BASE;
+       bl32_image_ep_info.spsr = arm_get_spsr_for_bl32_entry();
+
+       NOTICE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc);
+
+       SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0);
+
+       /*
+        * Tell BL31 where the non-trusted software image
+        * is located and the entry state information
+        */
+       bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
+       bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
+                                         DISABLE_ALL_EXCEPTIONS);
+       SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+       NOTICE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc);
+}
+
+void bl31_platform_setup(void)
+{
+       /* Initialize the gic cpu and distributor interfaces */
+       plat_arm_gic_driver_init();
+       plat_arm_gic_init();
+}
+
+void bl31_plat_runtime_setup(void)
+{
+}
+
+/*
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only intializes the MMU in a quick and dirty way.
+ */
+void bl31_plat_arch_setup(void)
+{
+       plat_arm_interconnect_init();
+       plat_arm_interconnect_enter_coherency();
+
+       arm_configure_mmu_el3(BL31_RO_BASE,
+                             BL31_COHERENT_RAM_LIMIT - BL31_RO_BASE,
+                             BL31_RO_BASE,
+                             BL31_RO_LIMIT,
+                             BL31_COHERENT_RAM_BASE,
+                             BL31_COHERENT_RAM_LIMIT);
+}
diff --git a/plat/xilinx/zynqmp/include/plat_macros.S b/plat/xilinx/zynqmp/include/plat_macros.S
new file mode 100644 (file)
index 0000000..e6c39bb
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __PLAT_MACROS_S__
+#define __PLAT_MACROS_S__
+
+#include <arm_macros.S>
+#include <cci_macros.S>
+#include "../zynqmp_def.h"
+
+       /* ---------------------------------------------
+        * The below required platform porting macro
+        * prints out relevant GIC registers whenever an
+        * unhandled exception is taken in BL31.
+        * Clobbers: x0 - x10, x16, sp
+        * ---------------------------------------------
+        */
+       .macro plat_print_gic_regs
+       mov_imm x17, BASE_GICC_BASE
+       mov_imm x16, BASE_GICD_BASE
+       arm_print_gic_regs
+       mov x0, x1
+       .endm
+
+#endif /* __PLAT_MACROS_S__ */
diff --git a/plat/xilinx/zynqmp/include/platform_def.h b/plat/xilinx/zynqmp/include/platform_def.h
new file mode 100644 (file)
index 0000000..947a0f3
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __PLATFORM_DEF_H__
+#define __PLATFORM_DEF_H__
+
+#include <arch.h>
+#include "../zynqmp_def.h"
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#define PLATFORM_STACK_SIZE 0x440
+
+#define PLATFORM_CORE_COUNT            4
+#define PLAT_NUM_POWER_DOMAINS         5
+#define PLAT_MAX_PWR_LVL               1
+#define PLAT_MAX_RET_STATE             1
+#define PLAT_MAX_OFF_STATE             2
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+
+#define ZYNQMP_BL31_SIZE       0x1b000
+/*
+ * Put BL31 at the top of the Trusted SRAM (just below the shared memory, if
+ * present). BL31_BASE is calculated using the current BL31 debug size plus a
+ * little space for growth.
+ */
+#if ZYNQMP_ATF_LOCATION_ID == ZYNQMP_IN_TRUSTED_SRAM
+# define BL31_BASE                     (ZYNQMP_TRUSTED_SRAM_LIMIT - \
+                                        ZYNQMP_BL31_SIZE)
+# define BL31_PROGBITS_LIMIT           (ZYNQMP_TRUSTED_SRAM_LIMIT - 0x6000)
+# define BL31_LIMIT                    ZYNQMP_TRUSTED_SRAM_LIMIT
+#elif ZYNQMP_ATF_LOCATION_ID == ZYNQMP_IN_TRUSTED_DRAM
+# define BL31_BASE                     (ZYNQMP_TRUSTED_DRAM_LIMIT - \
+                                        ZYNQMP_BL31_SIZE)
+# define BL31_PROGBITS_LIMIT           (ZYNQMP_TRUSTED_DRAM_LIMIT - 0x6000)
+# define BL31_LIMIT                    (ZYNQMP_TRUSTED_DRAM_BASE + \
+                                       ZYNQMP_TRUSTED_DRAM_SIZE)
+#else
+# error "Unsupported ZYNQMP_ATF_LOCATION_ID value"
+#endif
+
+/*******************************************************************************
+ * BL32 specific defines.
+ ******************************************************************************/
+/*
+ * On ZYNQMP, the TSP can execute either from Trusted SRAM or Trusted DRAM.
+ */
+#if ZYNQMP_TSP_RAM_LOCATION_ID == ZYNQMP_IN_TRUSTED_SRAM
+# define TSP_SEC_MEM_BASE              ZYNQMP_TRUSTED_SRAM_BASE
+# define TSP_SEC_MEM_SIZE              ZYNQMP_TRUSTED_SRAM_SIZE
+# define TSP_PROGBITS_LIMIT            (ZYNQMP_TRUSTED_SRAM_LIMIT - \
+                                        ZYNQMP_BL31_SIZE)
+# define BL32_BASE                     ZYNQMP_TRUSTED_SRAM_BASE
+# define BL32_LIMIT                    (ZYNQMP_TRUSTED_SRAM_LIMIT - \
+                                        ZYNQMP_BL31_SIZE)
+#elif ZYNQMP_TSP_RAM_LOCATION_ID == ZYNQMP_IN_TRUSTED_DRAM
+# define TSP_SEC_MEM_BASE              ZYNQMP_TRUSTED_DRAM_BASE
+# define TSP_SEC_MEM_SIZE              (ZYNQMP_TRUSTED_DRAM_LIMIT - \
+                                        ZYNQMP_BL31_SIZE)
+# define BL32_BASE                     ZYNQMP_TRUSTED_DRAM_BASE
+# define BL32_LIMIT                    (ZYNQMP_TRUSTED_DRAM_LIMIT - \
+                                        ZYNQMP_BL31_SIZE)
+#else
+# error "Unsupported ZYNQMP_TSP_RAM_LOCATION_ID value"
+#endif
+
+/*
+ * ID of the secure physical generic timer interrupt used by the TSP.
+ */
+#define TSP_IRQ_SEC_PHY_TIMER          ARM_IRQ_SEC_PHY_TIMER
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define ADDR_SPACE_SIZE                        (1ull << 32)
+#define MAX_XLAT_TABLES                        5
+#define MAX_MMAP_REGIONS               7
+
+#define CACHE_WRITEBACK_SHIFT   6
+#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
+
+#define PLAT_ARM_GICD_BASE     BASE_GICD_BASE
+#define PLAT_ARM_GICC_BASE     BASE_GICC_BASE
+/*
+ * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define PLAT_ARM_G1S_IRQS      ARM_IRQ_SEC_PHY_TIMER,  \
+                               IRQ_SEC_IPI_APU,        \
+                               ARM_IRQ_SEC_SGI_0,      \
+                               ARM_IRQ_SEC_SGI_1,      \
+                               ARM_IRQ_SEC_SGI_2,      \
+                               ARM_IRQ_SEC_SGI_3,      \
+                               ARM_IRQ_SEC_SGI_4,      \
+                               ARM_IRQ_SEC_SGI_5,      \
+                               ARM_IRQ_SEC_SGI_6,      \
+                               ARM_IRQ_SEC_SGI_7
+
+#define PLAT_ARM_G0_IRQS
+
+#endif /* __PLATFORM_DEF_H__ */
diff --git a/plat/xilinx/zynqmp/plat_psci.c b/plat/xilinx/zynqmp/plat_psci.c
new file mode 100644 (file)
index 0000000..d693a2d
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <arch_helpers.h>
+#include <errno.h>
+#include <assert.h>
+#include <debug.h>
+#include <gicv2.h>
+#include <mmio.h>
+#include <plat_arm.h>
+#include <platform.h>
+#include <psci.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "zynqmp_private.h"
+
+uintptr_t zynqmp_sec_entry;
+
+void zynqmp_cpu_standby(plat_local_state_t cpu_state)
+{
+       VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state);
+
+       dsb();
+       wfi();
+}
+
+static int zynqmp_nopmu_pwr_domain_on(u_register_t mpidr)
+{
+       uint32_t r;
+       unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr);
+
+       VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr);
+
+       if (cpu_id == -1)
+               return PSCI_E_INTERN_FAIL;
+
+       /* program RVBAR */
+       mmio_write_32(APU_RVBAR_L_0 + (cpu_id << 3), zynqmp_sec_entry);
+       mmio_write_32(APU_RVBAR_H_0 + (cpu_id << 3), zynqmp_sec_entry >> 32);
+
+       /* clear VINITHI */
+       r = mmio_read_32(APU_CONFIG_0);
+       r &= ~(1 << APU_CONFIG_0_VINITHI_SHIFT << cpu_id);
+       mmio_write_32(APU_CONFIG_0, r);
+
+       /* clear power down request */
+       r = mmio_read_32(APU_PWRCTL);
+       r &= ~(1 << cpu_id);
+       mmio_write_32(APU_PWRCTL, r);
+
+       /* power up island */
+       mmio_write_32(PMU_GLOBAL_REQ_PWRUP_EN, 1 << cpu_id);
+       mmio_write_32(PMU_GLOBAL_REQ_PWRUP_TRIG, 1 << cpu_id);
+       /* FIXME: we should have a way to break out */
+       while (mmio_read_32(PMU_GLOBAL_REQ_PWRUP_STATUS) & (1 << cpu_id))
+               ;
+
+       /* release core reset */
+       r = mmio_read_32(CRF_APB_RST_FPD_APU);
+       r &= ~((CRF_APB_RST_FPD_APU_ACPU_PWRON_RESET |
+                       CRF_APB_RST_FPD_APU_ACPU_RESET) << cpu_id);
+       mmio_write_32(CRF_APB_RST_FPD_APU, r);
+
+       return PSCI_E_SUCCESS;
+}
+
+static int zynqmp_pwr_domain_on(u_register_t mpidr)
+{
+       unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr);
+       const struct pm_proc *proc;
+
+       VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr);
+
+       if (cpu_id == -1)
+               return PSCI_E_INTERN_FAIL;
+
+       proc = pm_get_proc(cpu_id);
+
+       /* Send request to PMU to wake up selected APU CPU core */
+       pm_req_wakeup(proc->node_id, 1, zynqmp_sec_entry, REQ_ACK_NO);
+
+       return PSCI_E_SUCCESS;
+}
+
+static void zynqmp_nopmu_pwr_domain_off(const psci_power_state_t *target_state)
+{
+       uint32_t r;
+       unsigned int cpu_id = plat_my_core_pos();
+
+       for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+               VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+                       __func__, i, target_state->pwr_domain_state[i]);
+
+       /* Prevent interrupts from spuriously waking up this cpu */
+       gicv2_cpuif_disable();
+
+       /* set power down request */
+       r = mmio_read_32(APU_PWRCTL);
+       r |= (1 << cpu_id);
+       mmio_write_32(APU_PWRCTL, r);
+}
+
+static void zynqmp_pwr_domain_off(const psci_power_state_t *target_state)
+{
+       unsigned int cpu_id = plat_my_core_pos();
+       const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+       for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+               VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+                       __func__, i, target_state->pwr_domain_state[i]);
+
+       /* Prevent interrupts from spuriously waking up this cpu */
+       gicv2_cpuif_disable();
+
+       /*
+        * Send request to PMU to power down the appropriate APU CPU
+        * core.
+        * According to PSCI specification, CPU_off function does not
+        * have resume address and CPU core can only be woken up
+        * invoking CPU_on function, during which resume address will
+        * be set.
+        */
+       pm_self_suspend(proc->node_id, MAX_LATENCY, 0, 0);
+}
+
+static void zynqmp_nopmu_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+       uint32_t r;
+       unsigned int cpu_id = plat_my_core_pos();
+
+       for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+               VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+                       __func__, i, target_state->pwr_domain_state[i]);
+
+       /* set power down request */
+       r = mmio_read_32(APU_PWRCTL);
+       r |= (1 << cpu_id);
+       mmio_write_32(APU_PWRCTL, r);
+
+       /* program RVBAR */
+       mmio_write_32(APU_RVBAR_L_0 + (cpu_id << 3), zynqmp_sec_entry);
+       mmio_write_32(APU_RVBAR_H_0 + (cpu_id << 3), zynqmp_sec_entry >> 32);
+
+       /* clear VINITHI */
+       r = mmio_read_32(APU_CONFIG_0);
+       r &= ~(1 << APU_CONFIG_0_VINITHI_SHIFT << cpu_id);
+       mmio_write_32(APU_CONFIG_0, r);
+
+       /* enable power up on IRQ */
+       mmio_write_32(PMU_GLOBAL_REQ_PWRUP_EN, 1 << cpu_id);
+}
+
+static void zynqmp_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+       unsigned int cpu_id = plat_my_core_pos();
+       const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+       for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+               VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+                       __func__, i, target_state->pwr_domain_state[i]);
+
+       /* Send request to PMU to suspend this core */
+       pm_self_suspend(proc->node_id, MAX_LATENCY, 0, zynqmp_sec_entry);
+
+       /* APU is to be turned off */
+       if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+               /* Power down L2 cache */
+               pm_set_requirement(NODE_L2, 0, 0, REQ_ACK_NO);
+               /* Send request for OCM retention state */
+               set_ocm_retention();
+               /* disable coherency */
+               plat_arm_interconnect_exit_coherency();
+       }
+}
+
+static void zynqmp_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+       for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+               VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+                       __func__, i, target_state->pwr_domain_state[i]);
+
+       gicv2_cpuif_enable();
+       gicv2_pcpu_distif_init();
+}
+
+static void zynqmp_nopmu_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+       uint32_t r;
+       unsigned int cpu_id = plat_my_core_pos();
+
+       for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+               VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+                       __func__, i, target_state->pwr_domain_state[i]);
+
+       /* disable power up on IRQ */
+       mmio_write_32(PMU_GLOBAL_REQ_PWRUP_DIS, 1 << cpu_id);
+
+       /* clear powerdown bit */
+       r = mmio_read_32(APU_PWRCTL);
+       r &= ~(1 << cpu_id);
+       mmio_write_32(APU_PWRCTL, r);
+}
+
+static void zynqmp_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+       unsigned int cpu_id = plat_my_core_pos();
+       const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+       for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+               VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+                       __func__, i, target_state->pwr_domain_state[i]);
+
+       /* Clear the APU power control register for this cpu */
+       pm_client_wakeup(proc);
+
+       /* enable coherency */
+       plat_arm_interconnect_enter_coherency();
+}
+
+/*******************************************************************************
+ * ZynqMP handlers to shutdown/reboot the system
+ ******************************************************************************/
+static void __dead2 zynqmp_nopmu_system_off(void)
+{
+       ERROR("ZynqMP System Off: operation not handled.\n");
+
+       /* disable coherency */
+       plat_arm_interconnect_exit_coherency();
+
+       panic();
+}
+
+static void __dead2 zynqmp_system_off(void)
+{
+       /* disable coherency */
+       plat_arm_interconnect_exit_coherency();
+
+       /* Send the power down request to the PMU */
+       pm_system_shutdown(0);
+
+       while (1)
+               wfi();
+}
+
+static void __dead2 zynqmp_nopmu_system_reset(void)
+{
+       /*
+        * This currently triggers a system reset. I.e. the whole
+        * system will be reset! Including RPUs, PMU, PL, etc.
+        */
+
+       /* disable coherency */
+       plat_arm_interconnect_exit_coherency();
+
+       /* bypass RPLL (needed on 1.0 silicon) */
+       uint32_t reg = mmio_read_32(CRL_APB_RPLL_CTRL);
+       reg |= CRL_APB_RPLL_CTRL_BYPASS;
+       mmio_write_32(CRL_APB_RPLL_CTRL, reg);
+
+       /* trigger system reset */
+       mmio_write_32(CRL_APB_RESET_CTRL, CRL_APB_RESET_CTRL_SOFT_RESET);
+
+       while (1)
+               wfi();
+}
+
+static void __dead2 zynqmp_system_reset(void)
+{
+       /* disable coherency */
+       plat_arm_interconnect_exit_coherency();
+
+       /* Send the system reset request to the PMU */
+       pm_system_shutdown(1);
+
+       while (1)
+               wfi();
+}
+
+int zynqmp_validate_power_state(unsigned int power_state,
+                               psci_power_state_t *req_state)
+{
+       VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
+
+       /* FIXME: populate req_state */
+       return PSCI_E_SUCCESS;
+}
+
+int zynqmp_validate_ns_entrypoint(unsigned long ns_entrypoint)
+{
+       VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint);
+
+       /* FIXME: Actually validate */
+       return PSCI_E_SUCCESS;
+}
+
+void zynqmp_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+       req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE;
+       req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE;
+}
+
+/*******************************************************************************
+ * Export the platform handlers to enable psci to invoke them
+ ******************************************************************************/
+static const struct plat_psci_ops zynqmp_psci_ops = {
+       .cpu_standby                    = zynqmp_cpu_standby,
+       .pwr_domain_on                  = zynqmp_pwr_domain_on,
+       .pwr_domain_off                 = zynqmp_pwr_domain_off,
+       .pwr_domain_suspend             = zynqmp_pwr_domain_suspend,
+       .pwr_domain_on_finish           = zynqmp_pwr_domain_on_finish,
+       .pwr_domain_suspend_finish      = zynqmp_pwr_domain_suspend_finish,
+       .system_off                     = zynqmp_system_off,
+       .system_reset                   = zynqmp_system_reset,
+       .validate_power_state           = zynqmp_validate_power_state,
+       .validate_ns_entrypoint         = zynqmp_validate_ns_entrypoint,
+       .get_sys_suspend_power_state    = zynqmp_get_sys_suspend_power_state,
+};
+
+static const struct plat_psci_ops zynqmp_nopmu_psci_ops = {
+       .cpu_standby                    = zynqmp_cpu_standby,
+       .pwr_domain_on                  = zynqmp_nopmu_pwr_domain_on,
+       .pwr_domain_off                 = zynqmp_nopmu_pwr_domain_off,
+       .pwr_domain_suspend             = zynqmp_nopmu_pwr_domain_suspend,
+       .pwr_domain_on_finish           = zynqmp_pwr_domain_on_finish,
+       .pwr_domain_suspend_finish      = zynqmp_nopmu_pwr_domain_suspend_finish,
+       .system_off                     = zynqmp_nopmu_system_off,
+       .system_reset                   = zynqmp_nopmu_system_reset,
+       .validate_power_state           = zynqmp_validate_power_state,
+       .validate_ns_entrypoint         = zynqmp_validate_ns_entrypoint,
+       .get_sys_suspend_power_state    = zynqmp_get_sys_suspend_power_state,
+};
+
+/*******************************************************************************
+ * Export the platform specific power ops.
+ ******************************************************************************/
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+                       const struct plat_psci_ops **psci_ops)
+{
+       zynqmp_sec_entry = sec_entrypoint;
+
+       if (zynqmp_is_pmu_up())
+               *psci_ops = &zynqmp_psci_ops;
+       else
+               *psci_ops = &zynqmp_nopmu_psci_ops;
+
+       return 0;
+}
diff --git a/plat/xilinx/zynqmp/plat_topology.c b/plat/xilinx/zynqmp/plat_topology.c
new file mode 100644 (file)
index 0000000..34e7b53
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <platform_def.h>
+#include <psci.h>
+
+static const unsigned char plat_power_domain_tree_desc[] = {1, 4};
+
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+       return plat_power_domain_tree_desc;
+}
diff --git a/plat/xilinx/zynqmp/plat_zynqmp.c b/plat/xilinx/zynqmp/plat_zynqmp.c
new file mode 100644 (file)
index 0000000..38fa20f
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <plat_arm.h>
+
+int plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+       if (mpidr & MPIDR_CLUSTER_MASK)
+               return -1;
+
+       if ((mpidr & MPIDR_CPU_MASK) >= PLATFORM_CORE_COUNT)
+               return -1;
+
+       return plat_arm_calc_core_pos(mpidr);
+}
diff --git a/plat/xilinx/zynqmp/platform.mk b/plat/xilinx/zynqmp/platform.mk
new file mode 100644 (file)
index 0000000..0ffc0a9
--- /dev/null
@@ -0,0 +1,95 @@
+# Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# Neither the name of ARM nor the names of its contributors may be used
+# to endorse or promote products derived from this software without specific
+# prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+ENABLE_PLAT_COMPAT := 0
+PROGRAMMABLE_RESET_ADDRESS := 1
+PSCI_EXTENDED_STATE_ID := 1
+A53_DISABLE_NON_TEMPORAL_HINT := 0
+
+ZYNQMP_ATF_LOCATION    ?=      tsram
+ifeq (${ZYNQMP_ATF_LOCATION}, tsram)
+  ZYNQMP_ATF_LOCATION_ID := ZYNQMP_IN_TRUSTED_SRAM
+else ifeq (${ZYNQMP_ATF_LOCATION}, tdram)
+  ZYNQMP_ATF_LOCATION_ID := ZYNQMP_IN_TRUSTED_DRAM
+else
+  $(error "Unsupported ZYNQMP_ATF_LOCATION value")
+endif
+
+# On ZYNQMP, the TSP can execute either from Trusted SRAM or Trusted DRAM.
+# Trusted SRAM is the default.
+ZYNQMP_TSP_RAM_LOCATION        ?=      tsram
+ifeq (${ZYNQMP_TSP_RAM_LOCATION}, tsram)
+  ZYNQMP_TSP_RAM_LOCATION_ID := ZYNQMP_IN_TRUSTED_SRAM
+else ifeq (${ZYNQMP_TSP_RAM_LOCATION}, tdram)
+  ZYNQMP_TSP_RAM_LOCATION_ID := ZYNQMP_IN_TRUSTED_DRAM
+else
+  $(error "Unsupported ZYNQMP_TSP_RAM_LOCATION value")
+endif
+
+# Process flags
+$(eval $(call add_define,ZYNQMP_ATF_LOCATION_ID))
+$(eval $(call add_define,ZYNQMP_TSP_RAM_LOCATION_ID))
+
+PLAT_INCLUDES          :=      -Iinclude/plat/arm/common/                      \
+                               -Iinclude/plat/arm/common/aarch64/              \
+                               -Iplat/xilinx/zynqmp/include/                   \
+                               -Iplat/xilinx/zynqmp/pm_service/
+
+PLAT_BL_COMMON_SOURCES :=      lib/aarch64/xlat_tables.c                       \
+                               drivers/arm/gic/common/gic_common.c             \
+                               drivers/arm/gic/v2/gicv2_main.c                 \
+                               drivers/arm/gic/v2/gicv2_helpers.c              \
+                               drivers/cadence/uart/cdns_console.S             \
+                               drivers/console/console.S                       \
+                               plat/arm/common/aarch64/arm_common.c            \
+                               plat/arm/common/aarch64/arm_helpers.S           \
+                               plat/arm/common/arm_cci.c                       \
+                               plat/arm/common/arm_gicv2.c                     \
+                               plat/common/plat_gicv2.c                        \
+                               plat/common/aarch64/plat_common.c               \
+                               plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S     \
+                               plat/xilinx/zynqmp/aarch64/zynqmp_common.c
+
+BL31_SOURCES           +=      drivers/arm/cci/cci.c                           \
+                               lib/cpus/aarch64/aem_generic.S                  \
+                               lib/cpus/aarch64/cortex_a53.S                   \
+                               plat/common/aarch64/plat_psci_common.c          \
+                               plat/common/aarch64/platform_mp_stack.S         \
+                               plat/xilinx/zynqmp/bl31_zynqmp_setup.c          \
+                               plat/xilinx/zynqmp/plat_psci.c                  \
+                               plat/xilinx/zynqmp/plat_zynqmp.c                \
+                               plat/xilinx/zynqmp/plat_topology.c              \
+                               plat/xilinx/zynqmp/sip_svc_setup.c              \
+                               plat/xilinx/zynqmp/pm_service/pm_svc_main.c     \
+                               plat/xilinx/zynqmp/pm_service/pm_api_sys.c      \
+                               plat/xilinx/zynqmp/pm_service/pm_ipi.c          \
+                               plat/xilinx/zynqmp/pm_service/pm_client.c
+
+ifneq (${RESET_TO_BL31},1)
+  $(error "Using BL31 as the reset vector is only one option supported on ZynqMP. Please set RESET_TO_BL31 to 1.")
+endif
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
new file mode 100644 (file)
index 0000000..2f2e2ed
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+ * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * ZynqMP system level PM-API functions and communication with PMU via
+ * IPI interrupts
+ */
+
+#include <arch_helpers.h>
+#include <platform.h>
+#include "pm_client.h"
+#include "pm_common.h"
+#include "pm_api_sys.h"
+
+/**
+ * Assigning of argument values into array elements.
+ */
+#define PM_PACK_PAYLOAD1(pl, arg0) {   \
+       pl[0] = (uint32_t)(arg0);       \
+}
+
+#define PM_PACK_PAYLOAD2(pl, arg0, arg1) {     \
+       pl[1] = (uint32_t)(arg1);               \
+       PM_PACK_PAYLOAD1(pl, arg0);             \
+}
+
+#define PM_PACK_PAYLOAD3(pl, arg0, arg1, arg2) {       \
+       pl[2] = (uint32_t)(arg2);                       \
+       PM_PACK_PAYLOAD2(pl, arg0, arg1);               \
+}
+
+#define PM_PACK_PAYLOAD4(pl, arg0, arg1, arg2, arg3) { \
+       pl[3] = (uint32_t)(arg3);                       \
+       PM_PACK_PAYLOAD3(pl, arg0, arg1, arg2);         \
+}
+
+#define PM_PACK_PAYLOAD5(pl, arg0, arg1, arg2, arg3, arg4) {   \
+       pl[4] = (uint32_t)(arg4);                               \
+       PM_PACK_PAYLOAD4(pl, arg0, arg1, arg2, arg3);           \
+}
+
+#define PM_PACK_PAYLOAD6(pl, arg0, arg1, arg2, arg3, arg4, arg5) {     \
+       pl[5] = (uint32_t)(arg5);                                       \
+       PM_PACK_PAYLOAD5(pl, arg0, arg1, arg2, arg3, arg4);             \
+}
+
+/**
+ * pm_self_suspend() - PM call for processor to suspend itself
+ * @nid                Node id of the processor or subsystem
+ * @latency    Requested maximum wakeup latency (not supported)
+ * @state      Requested state (not supported)
+ * @address    Resume address
+ *
+ * This is a blocking call, it will return only once PMU has responded.
+ * On a wakeup, resume address will be automatically set by PMU.
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_self_suspend(enum pm_node_id nid,
+                                  unsigned int latency,
+                                  unsigned int state,
+                                  uintptr_t address)
+{
+       uint32_t payload[PAYLOAD_ARG_CNT];
+       unsigned int cpuid = plat_my_core_pos();
+       const struct pm_proc *proc = pm_get_proc(cpuid);
+
+       /*
+        * Do client specific suspend operations
+        * (e.g. set powerdown request bit)
+        */
+       pm_client_suspend(proc);
+       /* Send request to the PMU */
+       PM_PACK_PAYLOAD6(payload, PM_SELF_SUSPEND, proc->node_id, latency,
+                        state, address, (address >> 32));
+       return pm_ipi_send_sync(proc, payload, NULL);
+}
+
+/**
+ * pm_req_suspend() - PM call to request for another PU or subsystem to
+ *                   be suspended gracefully.
+ * @target     Node id of the targeted PU or subsystem
+ * @ack                Flag to specify whether acknowledge is requested
+ * @latency    Requested wakeup latency (not supported)
+ * @state      Requested state (not supported)
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_req_suspend(enum pm_node_id target,
+                                 enum pm_request_ack ack,
+                                 unsigned int latency, unsigned int state)
+{
+       uint32_t payload[PAYLOAD_ARG_CNT];
+
+       /* Send request to the PMU */
+       PM_PACK_PAYLOAD5(payload, PM_REQ_SUSPEND, target, ack, latency, state);
+       if (ack == REQ_ACK_BLOCKING)
+               return pm_ipi_send_sync(primary_proc, payload, NULL);
+       else
+               return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_req_wakeup() - PM call for processor to wake up selected processor
+ *                  or subsystem
+ * @target     Node id of the processor or subsystem to wake up
+ * @ack                Flag to specify whether acknowledge requested
+ * @set_address        Resume address presence indicator
+ *                             1 resume address specified, 0 otherwise
+ * @address    Resume address
+ *
+ * This API function is either used to power up another APU core for SMP
+ * (by PSCI) or to power up an entirely different PU or subsystem, such
+ * as RPU0, RPU, or PL_CORE_xx. Resume address for the target PU will be
+ * automatically set by PMU.
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_req_wakeup(enum pm_node_id target,
+                                unsigned int set_address,
+                                uintptr_t address,
+                                enum pm_request_ack ack)
+{
+       uint32_t payload[PAYLOAD_ARG_CNT];
+       uint64_t encoded_address;
+       const struct pm_proc *proc = pm_get_proc_by_node(target);
+
+       /* invoke APU-specific code for waking up another APU core */
+       pm_client_wakeup(proc);
+
+       /* encode set Address into 1st bit of address */
+       encoded_address = address;
+       encoded_address |= !!set_address;
+
+       /* Send request to the PMU to perform the wake of the PU */
+       PM_PACK_PAYLOAD5(payload, PM_REQ_WAKEUP, target, encoded_address,
+                        encoded_address >> 32, ack);
+
+       if (ack == REQ_ACK_BLOCKING)
+               return pm_ipi_send_sync(primary_proc, payload, NULL);
+       else
+               return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_force_powerdown() - PM call to request for another PU or subsystem to
+ *                       be powered down forcefully
+ * @target     Node id of the targeted PU or subsystem
+ * @ack                Flag to specify whether acknowledge is requested
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_force_powerdown(enum pm_node_id target,
+                                     enum pm_request_ack ack)
+{
+       uint32_t payload[PAYLOAD_ARG_CNT];
+
+       /* Send request to the PMU */
+       PM_PACK_PAYLOAD3(payload, PM_FORCE_POWERDOWN, target, ack);
+
+       if (ack == REQ_ACK_BLOCKING)
+               return pm_ipi_send_sync(primary_proc, payload, NULL);
+       else
+               return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_abort_suspend() - PM call to announce that a prior suspend request
+ *                     is to be aborted.
+ * @reason     Reason for the abort
+ *
+ * Calling PU expects the PMU to abort the initiated suspend procedure.
+ * This is a non-blocking call without any acknowledge.
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason)
+{
+       uint32_t payload[PAYLOAD_ARG_CNT];
+
+       /*
+        * Do client specific abort suspend operations
+        * (e.g. enable interrupts and clear powerdown request bit)
+        */
+       pm_client_abort_suspend();
+       /* Send request to the PMU */
+       /* TODO: allow passing the node ID of the affected CPU */
+       PM_PACK_PAYLOAD3(payload, PM_ABORT_SUSPEND, reason,
+                        primary_proc->node_id);
+       return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_set_wakeup_source() - PM call to specify the wakeup source while suspended
+ * @target     Node id of the targeted PU or subsystem
+ * @wkup_node  Node id of the wakeup peripheral
+ * @enable     Enable or disable the specified peripheral as wake source
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_set_wakeup_source(enum pm_node_id target,
+                                       enum pm_node_id wkup_node,
+                                       unsigned int enable)
+{
+       uint32_t payload[PAYLOAD_ARG_CNT];
+
+       PM_PACK_PAYLOAD4(payload, PM_SET_WAKEUP_SOURCE, target, wkup_node,
+                        enable);
+       return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_system_shutdown() - PM call to request a system shutdown or restart
+ * @restart    Shutdown or restart? 0 for shutdown, 1 for restart
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_system_shutdown(unsigned int restart)
+{
+       uint32_t payload[PAYLOAD_ARG_CNT];
+
+       PM_PACK_PAYLOAD2(payload, PM_SYSTEM_SHUTDOWN, restart);
+       return pm_ipi_send(primary_proc, payload);
+}
+
+/* APIs for managing PM slaves: */
+
+/**
+ * pm_req_node() - PM call to request a node with specific capabilities
+ * @nid                Node id of the slave
+ * @capabilities Requested capabilities of the slave
+ * @qos                Quality of service (not supported)
+ * @ack                Flag to specify whether acknowledge is requested
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_req_node(enum pm_node_id nid,
+                              unsigned int capabilities,
+                              unsigned int qos,
+                              enum pm_request_ack ack)
+{
+       uint32_t payload[PAYLOAD_ARG_CNT];
+
+       PM_PACK_PAYLOAD5(payload, PM_REQ_NODE, nid, capabilities, qos, ack);
+
+       if (ack == REQ_ACK_BLOCKING)
+               return pm_ipi_send_sync(primary_proc, payload, NULL);
+       else
+               return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_set_requirement() - PM call to set requirement for PM slaves
+ * @nid                Node id of the slave
+ * @capabilities Requested capabilities of the slave
+ * @qos                Quality of service (not supported)
+ * @ack                Flag to specify whether acknowledge is requested
+ *
+ * This API function is to be used for slaves a PU already has requested
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_set_requirement(enum pm_node_id nid,
+                                     unsigned int capabilities,
+                                     unsigned int qos,
+                                     enum pm_request_ack ack)
+{
+       uint32_t payload[PAYLOAD_ARG_CNT];
+
+       PM_PACK_PAYLOAD5(payload, PM_SET_REQUIREMENT, nid, capabilities, qos,
+                        ack);
+
+       if (ack == REQ_ACK_BLOCKING)
+               return pm_ipi_send_sync(primary_proc, payload, NULL);
+       else
+               return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_release_node() - PM call to release a node
+ * @nid                Node id of the slave
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_release_node(enum pm_node_id nid)
+{
+       uint32_t payload[PAYLOAD_ARG_CNT];
+
+       PM_PACK_PAYLOAD2(payload, PM_RELEASE_NODE, nid);
+       return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_set_max_latency() - PM call to set wakeup latency requirements
+ * @nid                Node id of the slave
+ * @latency    Requested maximum wakeup latency
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_set_max_latency(enum pm_node_id nid,
+                                     unsigned int latency)
+{
+       uint32_t payload[PAYLOAD_ARG_CNT];
+
+       PM_PACK_PAYLOAD3(payload, PM_SET_MAX_LATENCY, nid, latency);
+       return pm_ipi_send(primary_proc, payload);
+}
+
+/* Miscellaneous API functions */
+
+/**
+ * pm_get_api_version() - Get version number of PMU PM firmware
+ * @version    Returns 32-bit version number of PMU Power Management Firmware
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_get_api_version(unsigned int *version)
+{
+       uint32_t payload[PAYLOAD_ARG_CNT];
+
+       /* Send request to the PMU */
+       PM_PACK_PAYLOAD1(payload, PM_GET_API_VERSION);
+       return pm_ipi_send_sync(primary_proc, payload, version);
+}
+
+/**
+ * pm_set_configuration() - PM call to set system configuration
+ * @phys_addr  Physical 32-bit address of data structure in memory
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_set_configuration(unsigned int phys_addr)
+{
+       return PM_RET_ERROR_NOTSUPPORTED;
+}
+
+/**
+ * pm_get_node_status() - PM call to request a node's current power state
+ * @nid                Node id of the slave
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_get_node_status(enum pm_node_id nid)
+{
+       /* TODO: Add power state argument!! */
+       uint32_t payload[PAYLOAD_ARG_CNT];
+
+       PM_PACK_PAYLOAD2(payload, PM_GET_NODE_STATUS, nid);
+       return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_register_notifier() - Register the PU to be notified of PM events
+ * @nid                Node id of the slave
+ * @event      The event to be notified about
+ * @wake       Wake up on event
+ * @enable     Enable or disable the notifier
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_register_notifier(enum pm_node_id nid,
+                                       unsigned int event,
+                                       unsigned int wake,
+                                       unsigned int enable)
+{
+       return PM_RET_ERROR_NOTSUPPORTED;
+}
+
+/**
+ * pm_get_op_characteristic() - PM call to get a particular operating
+ *                             characteristic of a node
+ * @nid        Node ID
+ * @type       Operating characterstic type to be returned
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_get_op_characteristic(enum pm_node_id nid,
+                                           enum pm_opchar_type type)
+{
+       return PM_RET_ERROR_NOTSUPPORTED;
+}
+
+/* Direct-Control API functions */
+
+/**
+ * pm_reset_assert() - Assert reset
+ * @reset      Reset ID
+ * @assert     Assert (1) or de-assert (0)
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_reset_assert(unsigned int reset,
+                                  unsigned int assert)
+{
+       uint32_t payload[PAYLOAD_ARG_CNT];
+
+       /* Send request to the PMU */
+       PM_PACK_PAYLOAD3(payload, PM_RESET_ASSERT, reset, assert);
+       return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_reset_get_status() - Get current status of a reset line
+ * @reset      Reset ID
+ * @reset_status Returns current status of selected reset line
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_reset_get_status(unsigned int reset,
+                                      unsigned int *reset_status)
+{
+       uint32_t payload[PAYLOAD_ARG_CNT];
+
+       /* Send request to the PMU */
+       PM_PACK_PAYLOAD2(payload, PM_RESET_GET_STATUS, reset);
+       return pm_ipi_send_sync(primary_proc, payload, reset_status);
+}
+
+/**
+ * pm_mmio_write() - Perform write to protected mmio
+ * @address    Address to write to
+ * @mask       Mask to apply
+ * @value      Value to write
+ *
+ * This function provides access to PM-related control registers
+ * that may not be directly accessible by a particular PU.
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_mmio_write(uintptr_t address,
+                                unsigned int mask,
+                                unsigned int value)
+{
+       uint32_t payload[PAYLOAD_ARG_CNT];
+
+       /* Send request to the PMU */
+       PM_PACK_PAYLOAD4(payload, PM_MMIO_WRITE, address, mask, value);
+       return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_mmio_read() - Read value from protected mmio
+ * @address    Address to write to
+ * @value      Value to write
+ *
+ * This function provides access to PM-related control registers
+ * that may not be directly accessible by a particular PU.
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_mmio_read(uintptr_t address, unsigned int *value)
+{
+       uint32_t payload[PAYLOAD_ARG_CNT];
+
+       /* Send request to the PMU */
+       PM_PACK_PAYLOAD2(payload, PM_MMIO_READ, address);
+       return pm_ipi_send_sync(primary_proc, payload, value);
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
new file mode 100644 (file)
index 0000000..f0365cd
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PM_API_SYS_H_
+#define _PM_API_SYS_H_
+
+#include <stdint.h>
+#include "pm_defs.h"
+
+/**********************************************************
+ * System-level API function declarations
+ **********************************************************/
+enum pm_ret_status pm_req_suspend(enum pm_node_id nid,
+                                 enum pm_request_ack ack,
+                                 unsigned int latency,
+                                 unsigned int state);
+
+enum pm_ret_status pm_self_suspend(enum pm_node_id nid,
+                                  unsigned int latency,
+                                  unsigned int state,
+                                  uintptr_t address);
+
+enum pm_ret_status pm_force_powerdown(enum pm_node_id nid,
+                                     enum pm_request_ack ack);
+
+enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason);
+
+enum pm_ret_status pm_req_wakeup(enum pm_node_id nid,
+                                unsigned int set_address,
+                                uintptr_t address,
+                                enum pm_request_ack ack);
+
+enum pm_ret_status pm_set_wakeup_source(enum pm_node_id target,
+                                       enum pm_node_id wkup_node,
+                                       unsigned int enable);
+
+enum pm_ret_status pm_system_shutdown(unsigned int restart);
+
+enum pm_ret_status pm_init_suspend_cb(enum pm_suspend_reason reason,
+                                     unsigned int latency,
+                                     unsigned int state,
+                                     unsigned int timeout);
+
+/* API functions for managing PM Slaves */
+enum pm_ret_status pm_req_node(enum pm_node_id nid,
+                              unsigned int capabilities,
+                              unsigned int qos,
+                              enum pm_request_ack ack);
+enum pm_ret_status pm_release_node(enum pm_node_id nid);
+
+enum pm_ret_status pm_set_requirement(enum pm_node_id nid,
+                                     unsigned int capabilities,
+                                     unsigned int qos,
+                                     enum pm_request_ack ack);
+enum pm_ret_status pm_set_max_latency(enum pm_node_id nid,
+                                     unsigned int latency);
+
+/* Miscellaneous API functions */
+enum pm_ret_status pm_get_api_version(unsigned int *version);
+enum pm_ret_status pm_set_configuration(unsigned int phys_addr);
+enum pm_ret_status pm_get_node_status(enum pm_node_id node);
+enum pm_ret_status pm_register_notifier(enum pm_node_id nid,
+                                       unsigned int event,
+                                       unsigned int wake,
+                                       unsigned int enable);
+enum pm_ret_status pm_get_op_characteristic(enum pm_node_id nid,
+                                           enum pm_opchar_type type);
+enum pm_ret_status pm_acknowledge_cb(enum pm_node_id nid,
+                                    enum pm_ret_status status,
+                                    unsigned int oppoint);
+enum pm_ret_status pm_notify_cb(enum pm_node_id nid,
+                               unsigned int event,
+                               unsigned int oppoint);
+
+/* Direct-Control API functions */
+enum pm_ret_status pm_reset_assert(unsigned int reset_id,
+                                  unsigned int assert);
+enum pm_ret_status pm_reset_get_status(unsigned int reset_id,
+                                      unsigned int *reset_status);
+enum pm_ret_status pm_mmio_write(uintptr_t address,
+                                unsigned int mask,
+                                unsigned int value);
+enum pm_ret_status pm_mmio_read(uintptr_t address, unsigned int *value);
+#endif /* _PM_API_SYS_H_ */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.c b/plat/xilinx/zynqmp/pm_service/pm_client.c
new file mode 100644 (file)
index 0000000..eb986bc
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * APU specific definition of processors in the subsystem as well as functions
+ * for getting information about and changing state of the APU.
+ */
+
+#include <gicv2.h>
+#include <bl_common.h>
+#include <mmio.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_ipi.h"
+#include "../zynqmp_def.h"
+
+#define OCM_BANK_0     0xFFFC0000
+#define OCM_BANK_1     (OCM_BANK_0 + 0x10000)
+#define OCM_BANK_2     (OCM_BANK_1 + 0x10000)
+#define OCM_BANK_3     (OCM_BANK_2 + 0x10000)
+
+#define UNDEFINED_CPUID                (~0)
+
+/* Declaration of linker defined symbol */
+extern unsigned long __BL31_END__;
+extern const struct pm_ipi apu_ipi;
+
+/* Order in pm_procs_all array must match cpu ids */
+static const struct pm_proc const pm_procs_all[] = {
+       {
+               .node_id = NODE_APU_0,
+               .pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK,
+               .ipi = &apu_ipi,
+       },
+       {
+               .node_id = NODE_APU_1,
+               .pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK,
+               .ipi = &apu_ipi,
+       },
+       {
+               .node_id = NODE_APU_2,
+               .pwrdn_mask = APU_2_PWRCTL_CPUPWRDWNREQ_MASK,
+               .ipi = &apu_ipi,
+       },
+       {
+               .node_id = NODE_APU_3,
+               .pwrdn_mask = APU_3_PWRCTL_CPUPWRDWNREQ_MASK,
+               .ipi = &apu_ipi,
+       },
+};
+
+/**
+ * set_ocm_retention() - Configure OCM memory banks for retention
+ *
+ * APU specific requirements for suspend action:
+ * OCM has to enter retention state in order to preserve saved
+ * context after suspend request. OCM banks are determined by
+ * __BL31_END__ linker symbol.
+ *
+ * Return:     Returns status, either success or error+reason
+ */
+enum pm_ret_status set_ocm_retention(void)
+{
+       enum pm_ret_status ret;
+
+       /* OCM_BANK_0 will always be occupied */
+       ret = pm_set_requirement(NODE_OCM_BANK_0, PM_CAP_CONTEXT, 0,
+                                REQ_ACK_NO);
+
+       /* Check for other OCM banks  */
+       if ((unsigned long)&__BL31_END__ >= OCM_BANK_1)
+               ret = pm_set_requirement(NODE_OCM_BANK_1, PM_CAP_CONTEXT, 0,
+                                        REQ_ACK_NO);
+       if ((unsigned long)&__BL31_END__ >= OCM_BANK_2)
+               ret = pm_set_requirement(NODE_OCM_BANK_2, PM_CAP_CONTEXT, 0,
+                                        REQ_ACK_NO);
+       if ((unsigned long)&__BL31_END__ >= OCM_BANK_3)
+               ret = pm_set_requirement(NODE_OCM_BANK_3, PM_CAP_CONTEXT, 0,
+                                        REQ_ACK_NO);
+
+       return ret;
+}
+
+/**
+ * pm_get_proc() - returns pointer to the proc structure
+ * @cpuid:     id of the cpu whose proc struct pointer should be returned
+ *
+ * Return: pointer to a proc structure if proc is found, otherwise NULL
+ */
+const struct pm_proc *pm_get_proc(unsigned int cpuid)
+{
+       if (cpuid < ARRAY_SIZE(pm_procs_all))
+               return &pm_procs_all[cpuid];
+
+       return NULL;
+}
+
+/**
+ * pm_get_proc_by_node() - returns pointer to the proc structure
+ * @nid:       node id of the processor
+ *
+ * Return: pointer to a proc structure if proc is found, otherwise NULL
+ */
+const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid)
+{
+       for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
+               if (nid == pm_procs_all[i].node_id)
+                       return &pm_procs_all[i];
+       }
+       return NULL;
+}
+
+/**
+ * pm_get_cpuid() - get the local cpu ID for a global node ID
+ * @nid:       node id of the processor
+ *
+ * Return: the cpu ID (starting from 0) for the subsystem
+ */
+static unsigned int pm_get_cpuid(enum pm_node_id nid)
+{
+       for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
+               if (pm_procs_all[i].node_id == nid)
+                       return i;
+       }
+       return UNDEFINED_CPUID;
+}
+
+const struct pm_proc *primary_proc = &pm_procs_all[0];
+
+/**
+ * pm_client_suspend() - Client-specific suspend actions
+ *
+ * This function should contain any PU-specific actions
+ * required prior to sending suspend request to PMU
+ */
+void pm_client_suspend(const struct pm_proc *proc)
+{
+       /* Set powerdown request */
+       mmio_write_32(APU_PWRCTL, mmio_read_32(APU_PWRCTL) | proc->pwrdn_mask);
+}
+
+
+/**
+ * pm_client_abort_suspend() - Client-specific abort-suspend actions
+ *
+ * This function should contain any PU-specific actions
+ * required for aborting a prior suspend request
+ */
+void pm_client_abort_suspend(void)
+{
+       /* Enable interrupts at processor level (for current cpu) */
+       gicv2_cpuif_enable();
+       /* Clear powerdown request */
+       mmio_write_32(APU_PWRCTL,
+                mmio_read_32(APU_PWRCTL) & ~primary_proc->pwrdn_mask);
+}
+
+/**
+ * pm_client_wakeup() - Client-specific wakeup actions
+ *
+ * This function should contain any PU-specific actions
+ * required for waking up another APU core
+ */
+void pm_client_wakeup(const struct pm_proc *proc)
+{
+       unsigned int cpuid = pm_get_cpuid(proc->node_id);
+
+       if (cpuid == UNDEFINED_CPUID)
+               return;
+
+       /* clear powerdown bit for affected cpu */
+       uint32_t val = mmio_read_32(APU_PWRCTL);
+       val &= ~(proc->pwrdn_mask);
+       mmio_write_32(APU_PWRCTL, val);
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.h b/plat/xilinx/zynqmp/pm_service/pm_client.h
new file mode 100644 (file)
index 0000000..b9f196d
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Contains APU specific macros and macros to be defined depending on
+ * the execution environment.
+ */
+
+#ifndef _PM_CLIENT_H_
+#define _PM_CLIENT_H_
+
+#include "pm_defs.h"
+#include "pm_common.h"
+
+/* Functions to be implemented by each PU */
+enum pm_ret_status pm_ipi_send(const struct pm_proc *proc,
+                              uint32_t payload[PAYLOAD_ARG_CNT]);
+enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
+                                   uint32_t payload[PAYLOAD_ARG_CNT],
+                                   uint32_t *val);
+void pm_client_suspend(const struct pm_proc *proc);
+void pm_client_abort_suspend(void);
+void pm_client_wakeup(const struct pm_proc *proc);
+enum pm_ret_status set_ocm_retention(void);
+
+/* Global variables to be set in pm_client.c */
+extern const struct pm_proc *primary_proc;
+
+#endif /* _PM_CLIENT_H_ */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_common.h b/plat/xilinx/zynqmp/pm_service/pm_common.h
new file mode 100644 (file)
index 0000000..b432a83
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Contains definitions of commonly used macros and data types needed
+ * for PU Power Management. This file should be common for all PU's.
+ */
+
+#ifndef _PM_COMMON_H_
+#define _PM_COMMON_H_
+
+#include <debug.h>
+#include <stdint.h>
+#include "pm_defs.h"
+
+#define PAYLOAD_ARG_CNT                6U
+#define PAYLOAD_ARG_SIZE       4U      /* size in bytes */
+
+/**
+ * pm_ipi - struct for capturing IPI-channel specific info
+ * @mask       mask for enabling/disabling and triggering the IPI
+ * @base       base address for IPI
+ * @buffer_base        base address for payload buffer
+ */
+struct pm_ipi {
+       const unsigned int mask;
+       const uintptr_t base;
+       const uintptr_t buffer_base;
+};
+
+/**
+ * pm_proc - struct for capturing processor related info
+ * @node_id    node-ID of the processor
+ * @pwrdn_mask cpu-specific mask to be used for power control register
+ * @ipi                pointer to IPI channel structure
+ *             (in APU all processors share one IPI channel)
+ */
+struct pm_proc {
+       const enum pm_node_id node_id;
+       const unsigned int pwrdn_mask;
+       const struct pm_ipi *ipi;
+};
+
+const struct pm_proc *pm_get_proc(unsigned int cpuid);
+const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid);
+
+#endif /* _PM_COMMON_H_ */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_defs.h b/plat/xilinx/zynqmp/pm_service/pm_defs.h
new file mode 100644 (file)
index 0000000..08f4aab
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* ZynqMP power management enums and defines */
+
+#ifndef _PM_DEFS_H_
+#define _PM_DEFS_H_
+
+/*********************************************************************
+ * Macro definitions
+ ********************************************************************/
+
+/*
+ * Version number is a 32bit value, like:
+ * (PM_VERSION_MAJOR << 16) | PM_VERSION_MINOR
+ */
+#define PM_VERSION_MAJOR       0
+#define PM_VERSION_MINOR       2
+
+#define PM_VERSION     ((PM_VERSION_MAJOR << 16) | PM_VERSION_MINOR)
+
+/* Capabilities for RAM */
+#define PM_CAP_ACCESS  0x1U
+#define PM_CAP_CONTEXT 0x2U
+
+#define MAX_LATENCY    (~0U)
+#define MAX_QOS                100U
+
+/*********************************************************************
+ * Enum definitions
+ ********************************************************************/
+
+enum pm_api_id {
+       /* Miscellaneous API functions: */
+       PM_GET_API_VERSION = 1, /* Do not change or move */
+       PM_SET_CONFIGURATION,
+       PM_GET_NODE_STATUS,
+       PM_GET_OP_CHARACTERISTIC,
+       PM_REGISTER_NOTIFIER,
+       /* API for suspending of PUs: */
+       PM_REQ_SUSPEND,
+       PM_SELF_SUSPEND,
+       PM_FORCE_POWERDOWN,
+       PM_ABORT_SUSPEND,
+       PM_REQ_WAKEUP,
+       PM_SET_WAKEUP_SOURCE,
+       PM_SYSTEM_SHUTDOWN,
+       /* API for managing PM slaves: */
+       PM_REQ_NODE,
+       PM_RELEASE_NODE,
+       PM_SET_REQUIREMENT,
+       PM_SET_MAX_LATENCY,
+       /* Direct control API functions: */
+       PM_RESET_ASSERT,
+       PM_RESET_GET_STATUS,
+       PM_MMIO_WRITE,
+       PM_MMIO_READ,
+       PM_API_MAX
+};
+
+enum pm_node_id {
+       NODE_UNKNOWN = 0,
+       NODE_APU,
+       NODE_APU_0,
+       NODE_APU_1,
+       NODE_APU_2,
+       NODE_APU_3,
+       NODE_RPU,
+       NODE_RPU_0,
+       NODE_RPU_1,
+       NODE_PL,
+       NODE_FPD,
+       NODE_OCM_BANK_0,
+       NODE_OCM_BANK_1,
+       NODE_OCM_BANK_2,
+       NODE_OCM_BANK_3,
+       NODE_TCM_0_A,
+       NODE_TCM_0_B,
+       NODE_TCM_1_A,
+       NODE_TCM_1_B,
+       NODE_L2,
+       NODE_GPU_PP_0,
+       NODE_GPU_PP_1,
+       NODE_USB_0,
+       NODE_USB_1,
+       NODE_TTC_0,
+       NODE_TTC_1,
+       NODE_TTC_2,
+       NODE_TTC_3,
+       NODE_SATA,
+       NODE_ETH_0,
+       NODE_ETH_1,
+       NODE_ETH_2,
+       NODE_ETH_3,
+       NODE_UART_0,
+       NODE_UART_1,
+       NODE_SPI_0,
+       NODE_SPI_1,
+       NODE_I2C_0,
+       NODE_I2C_1,
+       NODE_SD_0,
+       NODE_SD_1,
+       NODE_DP,
+       NODE_GDMA,
+       NODE_ADMA,
+       NODE_NAND,
+       NODE_QSPI,
+       NODE_GPIO,
+       NODE_CAN_0,
+       NODE_CAN_1,
+       NODE_AFI,
+       NODE_APLL,
+       NODE_VPLL,
+       NODE_DPLL,
+       NODE_RPLL,
+       NODE_IOPLL,
+       NODE_DDR,
+};
+
+enum pm_request_ack {
+       REQ_ACK_NO = 1,
+       REQ_ACK_BLOCKING,
+       REQ_ACK_NON_BLOCKING,
+};
+
+enum pm_abort_reason {
+       ABORT_REASON_WKUP_EVENT = 100,
+       ABORT_REASON_PU_BUSY,
+       ABORT_REASON_NO_PWRDN,
+       ABORT_REASON_UNKNOWN,
+};
+
+enum pm_suspend_reason {
+       SUSPEND_REASON_PU_REQ = 201,
+       SUSPEND_REASON_ALERT,
+       SUSPEND_REASON_SYS_SHUTDOWN,
+};
+
+enum pm_ram_state {
+       PM_RAM_STATE_OFF = 1,
+       PM_RAM_STATE_RETENTION,
+       PM_RAM_STATE_ON,
+};
+
+enum pm_opchar_type {
+       PM_OPCHAR_TYPE_POWER = 1,
+       PM_OPCHAR_TYPE_ENERGY,
+       PM_OPCHAR_TYPE_TEMP,
+};
+
+/**
+ * @PM_RET_SUCCESS:            success
+ * @PM_RET_ERROR_ARGS:         illegal arguments provided
+ * @PM_RET_ERROR_ACCESS:       access rights violation
+ * @PM_RET_ERROR_TIMEOUT:      timeout in communication with PMU
+ * @PM_RET_ERROR_NOTSUPPORTED: feature not supported
+ * @PM_RET_ERROR_PROC:         node is not a processor node
+ * @PM_RET_ERROR_API_ID:       illegal API ID
+ * @PM_RET_ERROR_OTHER:                other error
+ */
+enum pm_ret_status {
+       PM_RET_SUCCESS,
+       PM_RET_ERROR_ARGS,
+       PM_RET_ERROR_ACCESS,
+       PM_RET_ERROR_TIMEOUT,
+       PM_RET_ERROR_NOTSUPPORTED,
+       PM_RET_ERROR_PROC,
+       PM_RET_ERROR_API_ID,
+       PM_RET_ERROR_FAILURE,
+       PM_RET_ERROR_COMMUNIC,
+       PM_RET_ERROR_DOUBLEREQ,
+       PM_RET_ERROR_OTHER,
+};
+
+/**
+ * @PM_INITIAL_BOOT:   boot is a fresh system startup
+ * @PM_RESUME:         boot is a resume
+ * @PM_BOOT_ERROR:     error, boot cause cannot be identified
+ */
+enum pm_boot_status {
+       PM_INITIAL_BOOT,
+       PM_RESUME,
+       PM_BOOT_ERROR,
+};
+
+#endif /* _PM_DEFS_H_ */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_ipi.c b/plat/xilinx/zynqmp/pm_service/pm_ipi.c
new file mode 100644 (file)
index 0000000..ef2b4fe
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <bakery_lock.h>
+#include <mmio.h>
+#include <platform.h>
+#include <arch_helpers.h>
+#include "pm_ipi.h"
+#include "../zynqmp_private.h"
+
+/* IPI message buffers */
+#define IPI_BUFFER_BASEADDR    0xFF990000U
+
+#define IPI_BUFFER_RPU_0_BASE  (IPI_BUFFER_BASEADDR + 0x0U)
+#define IPI_BUFFER_RPU_1_BASE  (IPI_BUFFER_BASEADDR + 0x200U)
+#define IPI_BUFFER_APU_BASE    (IPI_BUFFER_BASEADDR + 0x400U)
+#define IPI_BUFFER_PL_0_BASE   (IPI_BUFFER_BASEADDR + 0x600U)
+#define IPI_BUFFER_PL_1_BASE   (IPI_BUFFER_BASEADDR + 0x800U)
+#define IPI_BUFFER_PL_2_BASE   (IPI_BUFFER_BASEADDR + 0xA00U)
+#define IPI_BUFFER_PL_3_BASE   (IPI_BUFFER_BASEADDR + 0xC00U)
+#define IPI_BUFFER_PMU_BASE    (IPI_BUFFER_BASEADDR + 0xE00U)
+
+#define IPI_BUFFER_TARGET_RPU_0_OFFSET 0x0U
+#define IPI_BUFFER_TARGET_RPU_1_OFFSET 0x40U
+#define IPI_BUFFER_TARGET_APU_OFFSET   0x80U
+#define IPI_BUFFER_TARGET_PL_0_OFFSET  0xC0U
+#define IPI_BUFFER_TARGET_PL_1_OFFSET  0x100U
+#define IPI_BUFFER_TARGET_PL_2_OFFSET  0x140U
+#define IPI_BUFFER_TARGET_PL_3_OFFSET  0x180U
+#define IPI_BUFFER_TARGET_PMU_OFFSET   0x1C0U
+
+#define IPI_BUFFER_REQ_OFFSET  0x0U
+#define IPI_BUFFER_RESP_OFFSET 0x20U
+
+/* IPI Base Address */
+#define IPI_BASEADDR           0XFF300000
+
+/* APU's IPI registers */
+#define IPI_APU_ISR            (IPI_BASEADDR + 0X00000010)
+#define IPI_APU_IER            (IPI_BASEADDR + 0X00000018)
+#define IPI_APU_IDR            (IPI_BASEADDR + 0X0000001C)
+#define IPI_APU_ISR_PMU_0_MASK         0X00010000
+#define IPI_APU_IER_PMU_0_MASK         0X00010000
+
+#define IPI_TRIG_OFFSET                0
+#define IPI_OBS_OFFSET         4
+
+/* Power Management IPI interrupt number */
+#define PM_INT_NUM             0
+#define IPI_PMU_PM_INT_BASE    (IPI_PMU_0_TRIG + (PM_INT_NUM * 0x1000))
+#define IPI_PMU_PM_INT_MASK    (IPI_APU_ISR_PMU_0_MASK << PM_INT_NUM)
+#if (PM_INT_NUM < 0 || PM_INT_NUM > 3)
+       #error PM_INT_NUM value out of range
+#endif
+
+#define IPI_APU_MASK           1U
+
+static bakery_lock_t pm_secure_lock;
+
+const struct pm_ipi apu_ipi = {
+       .mask = IPI_APU_MASK,
+       .base = IPI_BASEADDR,
+       .buffer_base = IPI_BUFFER_APU_BASE,
+};
+
+/**
+ * pm_ipi_init() - Initialize IPI peripheral for communication with PMU
+ *
+ * @return     On success, the initialization function must return 0.
+ *             Any other return value will cause the framework to ignore
+ *             the service
+ *
+ * Enable interrupts at registered entrance in IPI peripheral
+ * Called from pm_setup initialization function
+ */
+int pm_ipi_init(void)
+{
+       bakery_lock_init(&pm_secure_lock);
+
+       /* IPI Interrupts Clear & Disable */
+       mmio_write_32(IPI_APU_ISR, 0xffffffff);
+       mmio_write_32(IPI_APU_IDR, 0xffffffff);
+
+       return 0;
+}
+
+/**
+ * pm_ipi_wait() - wait for pmu to handle request
+ * @proc       proc which is waiting for PMU to handle request
+ */
+static enum pm_ret_status pm_ipi_wait(const struct pm_proc *proc)
+{
+       int status;
+
+       /* Wait until previous interrupt is handled by PMU */
+       do {
+               status = mmio_read_32(proc->ipi->base + IPI_OBS_OFFSET) &
+                                       IPI_PMU_PM_INT_MASK;
+               /* TODO: 1) Use timer to add delay between read attempts */
+               /* TODO: 2) Return PM_RET_ERR_TIMEOUT if this times out */
+       } while (status);
+
+       return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_ipi_send_common() - Sends IPI request to the PMU
+ * @proc       Pointer to the processor who is initiating request
+ * @payload    API id and call arguments to be written in IPI buffer
+ *
+ * Send an IPI request to the power controller. Caller needs to hold
+ * the 'pm_secure_lock' lock.
+ *
+ * @return     Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ipi_send_common(const struct pm_proc *proc,
+                                            uint32_t payload[PAYLOAD_ARG_CNT])
+{
+       unsigned int offset = 0;
+       uintptr_t buffer_base = proc->ipi->buffer_base +
+                                       IPI_BUFFER_TARGET_PMU_OFFSET +
+                                       IPI_BUFFER_REQ_OFFSET;
+
+       /* Wait until previous interrupt is handled by PMU */
+       pm_ipi_wait(proc);
+
+       /* Write payload into IPI buffer */
+       for (size_t i = 0; i < PAYLOAD_ARG_CNT; i++) {
+               mmio_write_32(buffer_base + offset, payload[i]);
+               offset += PAYLOAD_ARG_SIZE;
+       }
+       /* Generate IPI to PMU */
+       mmio_write_32(proc->ipi->base + IPI_TRIG_OFFSET, IPI_PMU_PM_INT_MASK);
+
+       return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_ipi_send() - Sends IPI request to the PMU
+ * @proc       Pointer to the processor who is initiating request
+ * @payload    API id and call arguments to be written in IPI buffer
+ *
+ * Send an IPI request to the power controller.
+ *
+ * @return     Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_ipi_send(const struct pm_proc *proc,
+                              uint32_t payload[PAYLOAD_ARG_CNT])
+{
+       enum pm_ret_status ret;
+
+       bakery_lock_get(&pm_secure_lock);
+
+       ret = pm_ipi_send_common(proc, payload);
+
+       bakery_lock_release(&pm_secure_lock);
+
+       return ret;
+}
+
+
+/**
+ * pm_ipi_buff_read() - Reads IPI response after PMU has handled interrupt
+ * @proc       Pointer to the processor who is waiting and reading response
+ * @value      Used to return value from 2nd IPI buffer element (optional)
+ *
+ * @return     Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc,
+                                          unsigned int *value)
+{
+       uintptr_t buffer_base = proc->ipi->buffer_base +
+                               IPI_BUFFER_TARGET_PMU_OFFSET +
+                               IPI_BUFFER_RESP_OFFSET;
+
+       pm_ipi_wait(proc);
+
+       /*
+        * Read response from IPI buffer
+        * buf-0: success or error+reason
+        * buf-1: value
+        * buf-2: unused
+        * buf-3: unused
+        */
+       if (value != NULL)
+               *value = mmio_read_32(buffer_base + PAYLOAD_ARG_SIZE);
+
+       return mmio_read_32(buffer_base);
+}
+
+/**
+ * pm_ipi_send_sync() - Sends IPI request to the PMU
+ * @proc       Pointer to the processor who is initiating request
+ * @payload    API id and call arguments to be written in IPI buffer
+ * @value      Used to return value from 2nd IPI buffer element (optional)
+ *
+ * Send an IPI request to the power controller and wait for it to be handled.
+ *
+ * @return     Returns status, either success or error+reason and, optionally,
+ *             @value
+ */
+enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
+                                   uint32_t payload[PAYLOAD_ARG_CNT],
+                                   unsigned int *value)
+{
+       enum pm_ret_status ret;
+
+       bakery_lock_get(&pm_secure_lock);
+
+       ret = pm_ipi_send_common(proc, payload);
+       if (ret != PM_RET_SUCCESS)
+               goto unlock;
+
+       ret = pm_ipi_buff_read(proc, value);
+
+unlock:
+       bakery_lock_release(&pm_secure_lock);
+
+       return ret;
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_ipi.h b/plat/xilinx/zynqmp/pm_service/pm_ipi.h
new file mode 100644 (file)
index 0000000..d92e648
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PM_IPI_H_
+#define _PM_IPI_H_
+
+#include "pm_common.h"
+
+int pm_ipi_init(void);
+
+enum pm_ret_status pm_ipi_send(const struct pm_proc *proc,
+                              uint32_t payload[PAYLOAD_ARG_CNT]);
+enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
+                                   uint32_t payload[PAYLOAD_ARG_CNT],
+                                   unsigned int *value);
+
+#endif /* _PM_IPI_H_ */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
new file mode 100644 (file)
index 0000000..6744065
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Top-level SMC handler for ZynqMP power management calls and
+ * IPI setup functions for communication with PMU.
+ */
+
+#include <errno.h>
+#include <gic_common.h>
+#include <runtime_svc.h>
+#include <string.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_ipi.h"
+#include "../zynqmp_private.h"
+
+/* 0 - UP, !0 - DOWN */
+static int32_t pm_down = !0;
+
+/**
+ * pm_context - Structure which contains data for power management
+ * @api_version                version of PM API, must match with one on PMU side
+ * @payload            payload array used to store received
+ *                     data from ipi buffer registers
+ */
+static struct {
+       uint32_t api_version;
+       uint32_t payload[PAYLOAD_ARG_CNT];
+} pm_ctx;
+
+/**
+ * pm_setup() - PM service setup
+ *
+ * @return     On success, the initialization function must return 0.
+ *             Any other return value will cause the framework to ignore
+ *             the service
+ *
+ * Initialization functions for ZynqMP power management for
+ * communicaton with PMU.
+ *
+ * Called from sip_svc_setup initialization function with the
+ * rt_svc_init signature.
+ *
+ */
+int pm_setup(void)
+{
+       int status;
+
+       if (!zynqmp_is_pmu_up())
+               return -ENODEV;
+
+       status = pm_ipi_init();
+
+       if (status == 0)
+               INFO("BL31: PM Service Init Complete: API v%d.%d\n",
+                    PM_VERSION_MAJOR, PM_VERSION_MINOR);
+       else
+               INFO("BL31: PM Service Init Failed, Error Code %d!\n", status);
+
+       pm_down = status;
+
+       return status;
+}
+
+/**
+ * pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2.
+ * @smc_fid - Function Identifier
+ * @x1 - x4 - Arguments
+ * @cookie  - Unused
+ * @handler - Pointer to caller's context structure
+ *
+ * @return  - Unused
+ *
+ * Determines that smc_fid is valid and supported PM SMC Function ID from the
+ * list of pm_api_ids, otherwise completes the request with
+ * the unknown SMC Function ID
+ *
+ * The SMC calls for PM service are forwarded from SIP Service SMC handler
+ * function with rt_svc_handle signature
+ */
+uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
+                       uint64_t x4, void *cookie, void *handle, uint64_t flags)
+{
+       enum pm_ret_status ret;
+
+       uint32_t pm_arg[4];
+
+       /* Handle case where PM wasn't initialized properly */
+       if (pm_down)
+               SMC_RET1(handle, SMC_UNK);
+
+       pm_arg[0] = (uint32_t)x1;
+       pm_arg[1] = (uint32_t)(x1 >> 32);
+       pm_arg[2] = (uint32_t)x2;
+       pm_arg[3] = (uint32_t)(x2 >> 32);
+
+       switch (smc_fid & FUNCID_NUM_MASK) {
+       /* PM API Functions */
+       case PM_SELF_SUSPEND:
+               ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
+                                     pm_arg[3]);
+               SMC_RET1(handle, (uint64_t)ret);
+
+       case PM_REQ_SUSPEND:
+               ret = pm_req_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
+                                    pm_arg[3]);
+               SMC_RET1(handle, (uint64_t)ret);
+
+       case PM_REQ_WAKEUP:
+               ret = pm_req_wakeup(pm_arg[0], pm_arg[1], pm_arg[2],
+                                   pm_arg[3]);
+               SMC_RET1(handle, (uint64_t)ret);
+
+       case PM_FORCE_POWERDOWN:
+               ret = pm_force_powerdown(pm_arg[0], pm_arg[1]);
+               SMC_RET1(handle, (uint64_t)ret);
+
+       case PM_ABORT_SUSPEND:
+               ret = pm_abort_suspend(pm_arg[0]);
+               SMC_RET1(handle, (uint64_t)ret);
+
+       case PM_SET_WAKEUP_SOURCE:
+               ret = pm_set_wakeup_source(pm_arg[0], pm_arg[1], pm_arg[2]);
+               SMC_RET1(handle, (uint64_t)ret);
+
+       case PM_SYSTEM_SHUTDOWN:
+               ret = pm_system_shutdown(pm_arg[0]);
+               SMC_RET1(handle, (uint64_t)ret);
+
+       case PM_REQ_NODE:
+               ret = pm_req_node(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]);
+               SMC_RET1(handle, (uint64_t)ret);
+
+       case PM_RELEASE_NODE:
+               ret = pm_release_node(pm_arg[0]);
+               SMC_RET1(handle, (uint64_t)ret);
+
+       case PM_SET_REQUIREMENT:
+               ret = pm_set_requirement(pm_arg[0], pm_arg[1], pm_arg[2],
+                                        pm_arg[3]);
+               SMC_RET1(handle, (uint64_t)ret);
+
+       case PM_SET_MAX_LATENCY:
+               ret = pm_set_max_latency(pm_arg[0], pm_arg[1]);
+               SMC_RET1(handle, (uint64_t)ret);
+
+       case PM_GET_API_VERSION:
+               /* Check is PM API version already verified */
+               if (pm_ctx.api_version == PM_VERSION)
+                       SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
+                                ((uint64_t)PM_VERSION << 32));
+
+               ret = pm_get_api_version(&pm_ctx.api_version);
+               SMC_RET1(handle, (uint64_t)ret |
+                        ((uint64_t)pm_ctx.api_version << 32));
+
+       case PM_SET_CONFIGURATION:
+               ret = pm_set_configuration(pm_arg[0]);
+               SMC_RET1(handle, (uint64_t)ret);
+
+       case PM_GET_NODE_STATUS:
+               ret = pm_get_node_status(pm_arg[0]);
+               SMC_RET1(handle, (uint64_t)ret);
+
+       case PM_GET_OP_CHARACTERISTIC:
+               ret = pm_get_op_characteristic(pm_arg[0], pm_arg[1]);
+               SMC_RET1(handle, (uint64_t)ret);
+
+       case PM_REGISTER_NOTIFIER:
+               ret = pm_register_notifier(pm_arg[0], pm_arg[1], pm_arg[2],
+                                          pm_arg[3]);
+               SMC_RET1(handle, (uint64_t)ret);
+
+       case PM_RESET_ASSERT:
+               ret = pm_reset_assert(pm_arg[0], pm_arg[1]);
+               SMC_RET1(handle, (uint64_t)ret);
+
+       case PM_RESET_GET_STATUS:
+       {
+               uint32_t reset_status;
+
+               ret = pm_reset_get_status(pm_arg[0], &reset_status);
+               SMC_RET1(handle, (uint64_t)ret |
+                        ((uint64_t)reset_status << 32));
+       }
+
+       /* PM memory access functions */
+       case PM_MMIO_WRITE:
+               ret = pm_mmio_write(pm_arg[0], pm_arg[1], pm_arg[2]);
+               SMC_RET1(handle, (uint64_t)ret);
+
+       case PM_MMIO_READ:
+       {
+               uint32_t value;
+
+               ret = pm_mmio_read(pm_arg[0], &value);
+               SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+       }
+       default:
+               WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid);
+               SMC_RET1(handle, SMC_UNK);
+       }
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.h b/plat/xilinx/zynqmp/pm_service/pm_svc_main.h
new file mode 100644 (file)
index 0000000..26985a2
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PM_SVC_MAIN_H_
+#define _PM_SVC_MAIN_H_
+
+#include "pm_common.h"
+
+int pm_setup(void);
+uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
+                       uint64_t x4, void *cookie, void *handle,
+                       uint64_t flags);
+
+#endif /*  _PM_SVC_MAIN_H_ */
diff --git a/plat/xilinx/zynqmp/sip_svc_setup.c b/plat/xilinx/zynqmp/sip_svc_setup.c
new file mode 100644 (file)
index 0000000..8bcfa6e
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Top level SMC handler for SiP calls. Dispatch PM calls to PM SMC handler. */
+
+#include <runtime_svc.h>
+#include <uuid.h>
+#include "pm_svc_main.h"
+
+/* SMC function IDs for SiP Service queries */
+#define ZYNQMP_SIP_SVC_CALL_COUNT      0x8200ff00
+#define ZYNQMP_SIP_SVC_UID             0x8200ff01
+#define ZYNQMP_SIP_SVC_VERSION         0x8200ff03
+
+/* SiP Service Calls version numbers */
+#define SIP_SVC_VERSION_MAJOR  0
+#define SIP_SVC_VERSION_MINOR  1
+
+/* These macros are used to identify PM calls from the SMC function ID */
+#define PM_FID_MASK    0xf000u
+#define PM_FID_VALUE   0u
+#define is_pm_fid(_fid) (((_fid) & PM_FID_MASK) == PM_FID_VALUE)
+
+/* SiP Service UUID */
+DEFINE_SVC_UUID(zynqmp_sip_uuid,
+               0x2a1d9b5c, 0x8605, 0x4023, 0xa6, 0x1b,
+               0xb9, 0x25, 0x82, 0x2d, 0xe3, 0xa5);
+
+/**
+ * sip_svc_setup() - Setup SiP Service
+ *
+ * Invokes PM setup
+ */
+static int32_t sip_svc_setup(void)
+{
+       /* PM implementation as SiP Service */
+       pm_setup();
+
+       return 0;
+}
+
+/**
+ * sip_svc_smc_handler() - Top-level SiP Service SMC handler
+ *
+ * Handler for all SiP SMC calls. Handles standard SIP requests
+ * and calls PM SMC handler if the call is for a PM-API function.
+ */
+uint64_t sip_svc_smc_handler(uint32_t smc_fid,
+                            uint64_t x1,
+                            uint64_t x2,
+                            uint64_t x3,
+                            uint64_t x4,
+                            void *cookie,
+                            void *handle,
+                            uint64_t flags)
+{
+       /* Let PM SMC handler deal with PM-related requests */
+       if (is_pm_fid(smc_fid)) {
+               return pm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
+                                     flags);
+       }
+
+       switch (smc_fid) {
+       case ZYNQMP_SIP_SVC_CALL_COUNT:
+               /* PM functions + default functions */
+               SMC_RET1(handle, PM_API_MAX + 2);
+
+       case ZYNQMP_SIP_SVC_UID:
+               SMC_UUID_RET(handle, zynqmp_sip_uuid);
+
+       case ZYNQMP_SIP_SVC_VERSION:
+               SMC_RET2(handle, SIP_SVC_VERSION_MAJOR, SIP_SVC_VERSION_MINOR);
+
+       default:
+               WARN("Unimplemented SiP Service Call: 0x%x\n", smc_fid);
+               SMC_RET1(handle, SMC_UNK);
+       }
+}
+
+/* Register PM Service Calls as runtime service */
+DECLARE_RT_SVC(
+               sip_svc,
+               OEN_SIP_START,
+               OEN_SIP_END,
+               SMC_TYPE_FAST,
+               sip_svc_setup,
+               sip_svc_smc_handler);
diff --git a/plat/xilinx/zynqmp/tsp/tsp-zynqmp.mk b/plat/xilinx/zynqmp/tsp/tsp-zynqmp.mk
new file mode 100644 (file)
index 0000000..a9ebe60
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# Neither the name of ARM nor the names of its contributors may be used
+# to endorse or promote products derived from this software without specific
+# prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+# TSP source files specific to ZynqMP platform
+BL32_SOURCES           +=      plat/common/aarch64/platform_mp_stack.S         \
+                               plat/xilinx/zynqmp/tsp/tsp_plat_setup.c
diff --git a/plat/xilinx/zynqmp/tsp/tsp_plat_setup.c b/plat/xilinx/zynqmp/tsp/tsp_plat_setup.c
new file mode 100644 (file)
index 0000000..291ccba
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <bl_common.h>
+#include <console.h>
+#include <debug.h>
+#include <platform_tsp.h>
+#include <xlat_tables.h>
+#include <plat_arm.h>
+#include "../zynqmp_def.h"
+#include "../zynqmp_private.h"
+
+/*
+ * The next 3 constants identify the extents of the code & RO data region and
+ * the limit of the BL32 image. These addresses are used by the MMU setup code
+ * and therefore they must be page-aligned.  It is the responsibility of the
+ * linker script to ensure that __RO_START__, __RO_END__ & & __BL32_END__
+ * linker symbols refer to page-aligned addresses.
+ */
+#define BL32_RO_BASE (unsigned long)(&__RO_START__)
+#define BL32_RO_LIMIT (unsigned long)(&__RO_END__)
+#define BL32_END (unsigned long)(&__BL32_END__)
+
+
+#if USE_COHERENT_MEM
+/*
+ * The next 2 constants identify the extents of the coherent memory region.
+ * These addresses are used by the MMU setup code and therefore they must be
+ * page-aligned.  It is the responsibility of the linker script to ensure that
+ * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols refer to
+ * page-aligned addresses.
+ */
+#define BL32_COHERENT_RAM_BASE (unsigned long)(&__COHERENT_RAM_START__)
+#define BL32_COHERENT_RAM_LIMIT (unsigned long)(&__COHERENT_RAM_END__)
+#endif
+
+/*******************************************************************************
+ * Initialize the UART
+ ******************************************************************************/
+void tsp_early_platform_setup(void)
+{
+       /*
+        * Initialize a different console than already in use to display
+        * messages from TSP
+        */
+       console_init(ZYNQMP_UART0_BASE, zynqmp_get_uart_clk(),
+                    ZYNQMP_UART_BAUDRATE);
+
+       /* Initialize the platform config for future decision making */
+       zynqmp_config_setup();
+}
+
+/*******************************************************************************
+ * Perform platform specific setup placeholder
+ ******************************************************************************/
+void tsp_platform_setup(void)
+{
+       plat_arm_gic_driver_init();
+       plat_arm_gic_init();
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only intializes the MMU
+ ******************************************************************************/
+void tsp_plat_arch_setup(void)
+{
+       arm_configure_mmu_el1(BL32_RO_BASE,
+                             (BL32_END - BL32_RO_BASE),
+                             BL32_RO_BASE,
+                             BL32_RO_LIMIT
+#if USE_COHERENT_MEM
+                             , BL32_COHERENT_RAM_BASE,
+                             BL32_COHERENT_RAM_LIMIT
+#endif
+                             );
+}
diff --git a/plat/xilinx/zynqmp/zynqmp_def.h b/plat/xilinx/zynqmp/zynqmp_def.h
new file mode 100644 (file)
index 0000000..32190e4
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ZYNQMP_DEF_H__
+#define __ZYNQMP_DEF_H__
+
+#include <common_def.h>
+
+/* Firmware Image Package */
+#define ZYNQMP_PRIMARY_CPU             0
+
+/* Memory location options for Shared data and TSP in ZYNQMP */
+#define ZYNQMP_IN_TRUSTED_SRAM         0
+#define ZYNQMP_IN_TRUSTED_DRAM         1
+
+/*******************************************************************************
+ * ZYNQMP memory map related constants
+ ******************************************************************************/
+
+#define ZYNQMP_TRUSTED_SRAM_BASE       0xFFFC0000
+#define ZYNQMP_TRUSTED_SRAM_SIZE       0x00040000
+#define ZYNQMP_TRUSTED_SRAM_LIMIT      (ZYNQMP_TRUSTED_SRAM_BASE + \
+                                        ZYNQMP_TRUSTED_SRAM_SIZE)
+
+
+/* Location of trusted dram on the base zynqmp */
+#define ZYNQMP_TRUSTED_DRAM_BASE       0x30000000 /* Can't overlap TZROM area */
+#define ZYNQMP_TRUSTED_DRAM_SIZE       0x10000000
+#define ZYNQMP_TRUSTED_DRAM_LIMIT      (ZYNQMP_TRUSTED_DRAM_BASE + \
+                                        ZYNQMP_TRUSTED_DRAM_SIZE)
+
+/* Aggregate of all devices in the first GB */
+#define DEVICE0_BASE           0xFF000000
+#define DEVICE0_SIZE           0x00E00000
+#define DEVICE1_BASE           0xF9000000
+#define DEVICE1_SIZE           0x01000000
+
+/* For cpu reset APU space here too 0xFE5F1000 CRF_APB*/
+#define CRF_APB_BASE           0xFD1A0000
+#define CRF_APB_SIZE           0x00600000
+
+/* CRF registers and bitfields */
+#define CRF_APB_RST_FPD_APU    (CRF_APB_BASE + 0X00000104)
+
+#define CRF_APB_RST_FPD_APU_ACPU_RESET         (1 << 0)
+#define CRF_APB_RST_FPD_APU_ACPU_PWRON_RESET   (1 << 10)
+
+/* CRL registers and bitfields */
+#define CRL_APB_BASE                   0xFF5E0000
+#define CRL_APB_RPLL_CTRL              (CRL_APB_BASE + 0x30)
+#define CRL_APB_TIMESTAMP_REF_CTRL     (CRL_APB_BASE + 0x128)
+#define CRL_APB_RESET_CTRL             (CRL_APB_BASE + 0x218)
+
+#define CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT  (1 << 24)
+
+#define CRL_APB_RPLL_CTRL_BYPASS       (1 << 3)
+
+#define CRL_APB_RESET_CTRL_SOFT_RESET  (1 << 4)
+
+/* system counter registers and bitfields */
+#define IOU_SCNTRS_BASE                        0xFF260000
+#define IOU_SCNTRS_CONTROL             (IOU_SCNTRS_BASE + 0)
+#define IOU_SCNTRS_BASEFREQ            (IOU_SCNTRS_BASE + 0x20)
+
+#define IOU_SCNTRS_CONTROL_EN          (1 << 0)
+
+/* APU registers and bitfields */
+#define APU_BASE               0xFD5C0000
+#define APU_CONFIG_0           (APU_BASE + 0x20)
+#define APU_RVBAR_L_0          (APU_BASE + 0x40)
+#define APU_RVBAR_H_0          (APU_BASE + 0x44)
+#define APU_PWRCTL             (APU_BASE + 0x90)
+
+#define APU_CONFIG_0_VINITHI_SHIFT     8
+#define APU_0_PWRCTL_CPUPWRDWNREQ_MASK         1
+#define APU_1_PWRCTL_CPUPWRDWNREQ_MASK         2
+#define APU_2_PWRCTL_CPUPWRDWNREQ_MASK         4
+#define APU_3_PWRCTL_CPUPWRDWNREQ_MASK         8
+
+/* PMU registers and bitfields */
+#define PMU_GLOBAL_BASE                        0xFFD80000
+#define PMU_GLOBAL_CNTRL               (PMU_GLOBAL_BASE + 0)
+#define PMU_GLOBAL_REQ_PWRUP_STATUS    (PMU_GLOBAL_BASE + 0x110)
+#define PMU_GLOBAL_REQ_PWRUP_EN                (PMU_GLOBAL_BASE + 0x118)
+#define PMU_GLOBAL_REQ_PWRUP_DIS       (PMU_GLOBAL_BASE + 0x11c)
+#define PMU_GLOBAL_REQ_PWRUP_TRIG      (PMU_GLOBAL_BASE + 0x120)
+
+#define PMU_GLOBAL_CNTRL_FW_IS_PRESENT (1 << 4)
+
+#define DRAM1_BASE             0x00000000ull
+#define DRAM1_SIZE             0x10000000ull
+#define DRAM1_END              (DRAM1_BASE + DRAM1_SIZE - 1)
+
+#define DRAM_BASE              DRAM1_BASE
+#define DRAM_SIZE              DRAM1_SIZE
+
+/* Load address of BL33 in the ZYNQMP port */
+#define PLAT_ARM_NS_IMAGE_OFFSET       (DRAM1_BASE + 0x8000000) /* DRAM + 128MB */
+
+/*******************************************************************************
+ * CCI-400 related constants
+ ******************************************************************************/
+#define PLAT_ARM_CCI_BASE              0xFD6E0000
+#define PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX      3
+#define PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX      4
+
+/*******************************************************************************
+ * GIC-400 & interrupt handling related constants
+ ******************************************************************************/
+#define BASE_GICD_BASE         0xF9010000
+#define BASE_GICC_BASE         0xF9020000
+#define BASE_GICH_BASE         0xF9040000
+#define BASE_GICV_BASE         0xF9060000
+
+#define IRQ_SEC_IPI_APU                        67
+#define ARM_IRQ_SEC_PHY_TIMER          29
+
+#define ARM_IRQ_SEC_SGI_0              8
+#define ARM_IRQ_SEC_SGI_1              9
+#define ARM_IRQ_SEC_SGI_2              10
+#define ARM_IRQ_SEC_SGI_3              11
+#define ARM_IRQ_SEC_SGI_4              12
+#define ARM_IRQ_SEC_SGI_5              13
+#define ARM_IRQ_SEC_SGI_6              14
+#define ARM_IRQ_SEC_SGI_7              15
+
+#define MAX_INTR_EL3                   128
+
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define ZYNQMP_UART0_BASE              0xFF000000
+#define ZYNQMP_UART1_BASE              0xFF001000
+
+#define PLAT_ARM_CRASH_UART_BASE       ZYNQMP_UART0_BASE
+/* impossible to call C routine how it is done now - hardcode any value */
+#define        PLAT_ARM_CRASH_UART_CLK_IN_HZ   100000000 /* FIXME */
+
+/* Must be non zero */
+#define ZYNQMP_UART_BAUDRATE   115200
+#define ARM_CONSOLE_BAUDRATE   ZYNQMP_UART_BAUDRATE
+
+/* Silicon version detection */
+#define ZYNQMP_SILICON_VER_MASK                0xF000
+#define ZYNQMP_SILICON_VER_SHIFT       12
+#define ZYNQMP_CSU_VERSION_SILICON     0
+#define ZYNQMP_CSU_VERSION_EP108       1
+#define ZYNQMP_CSU_VERSION_VELOCE      2
+#define ZYNQMP_CSU_VERSION_QEMU                3
+
+#define ZYNQMP_RTL_VER_MASK            0xFF0
+#define ZYNQMP_RTL_VER_SHIFT           4
+
+#define ZYNQMP_PS_VER_MASK             0xF
+#define ZYNQMP_PS_VER_SHIFT            0
+
+#define ZYNQMP_CSU_BASEADDR            0xFFCA0000
+#define ZYNQMP_CSU_IDCODE_OFFSET       0x40
+
+#define ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT      0
+#define ZYNQMP_CSU_IDCODE_XILINX_ID_MASK       (0xFFF << ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT)
+#define ZYNQMP_CSU_IDCODE_XILINX_ID            0x093
+
+#define ZYNQMP_CSU_IDCODE_SVD_SHIFT            12
+#define ZYNQMP_CSU_IDCODE_SVD_MASK             (0xE << ZYNQMP_CSU_IDCODE_SVD_SHIFT)
+#define ZYNQMP_CSU_IDCODE_DEVICE_CODE_SHIFT    15
+#define ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK     (0xF << ZYNQMP_CSU_IDCODE_DEVICE_CODE_SHIFT)
+#define ZYNQMP_CSU_IDCODE_SUB_FAMILY_SHIFT     19
+#define ZYNQMP_CSU_IDCODE_SUB_FAMILY_MASK      (0x3 << ZYNQMP_CSU_IDCODE_SUB_FAMILY_SHIFT)
+#define ZYNQMP_CSU_IDCODE_FAMILY_SHIFT         21
+#define ZYNQMP_CSU_IDCODE_FAMILY_MASK          (0x7F << ZYNQMP_CSU_IDCODE_FAMILY_SHIFT)
+#define ZYNQMP_CSU_IDCODE_FAMILY               0x23
+
+#define ZYNQMP_CSU_IDCODE_REVISION_SHIFT       28
+#define ZYNQMP_CSU_IDCODE_REVISION_MASK                (0xF << ZYNQMP_CSU_IDCODE_REVISION_SHIFT)
+#define ZYNQMP_CSU_IDCODE_REVISION             0
+
+#define ZYNQMP_CSU_VERSION_OFFSET      0x44
+
+#endif /* __ZYNQMP_DEF_H__ */
diff --git a/plat/xilinx/zynqmp/zynqmp_private.h b/plat/xilinx/zynqmp/zynqmp_private.h
new file mode 100644 (file)
index 0000000..1f5be39
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ZYNQMP_PRIVATE_H__
+#define __ZYNQMP_PRIVATE_H__
+
+#include <interrupt_mgmt.h>
+
+void zynqmp_config_setup(void);
+
+/* ZynqMP specific functions */
+unsigned int zynqmp_get_uart_clk(void);
+int zynqmp_is_pmu_up(void);
+
+#endif /* __ZYNQMP_PRIVATE_H__ */